修复退款审核详情关联与空值展示

This commit is contained in:
czl231
2026-08-17 00:44:49 +08:00
parent 64248973ee
commit 74efb323f0
10 changed files with 543 additions and 11 deletions

View File

@@ -1,16 +1,304 @@
package payment
import (
"encoding/json"
"strconv"
"strings"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/infra"
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
paylogic "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/payment"
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
"github.com/gin-gonic/gin"
)
func ListRefund(ctx *gin.Context) { common.ListResource(ctx, &models.PaymentRefund{}) }
func GetRefund(ctx *gin.Context) { common.GetResource(ctx, &models.PaymentRefund{}) }
// paymentRefundDisplay 在退款事实之外附加财务审核所需的可读关系名称。
type paymentRefundDisplay struct {
models.PaymentRefund
BusinessDisplayName string `json:"business_display_name"`
UserDisplayName string `json:"user_display_name"`
ReviewerDisplayName string `json:"reviewer_display_name"`
RefundProductSummary string `json:"refund_product_summary"`
}
// refundEcProductSnapshot 是商城退款读取成交商品名称所需的最小快照结构。
type refundEcProductSnapshot struct {
Name string `json:"name"`
}
// ListRefund 返回退款列表,并批量解析原订单号和申请用户姓名。
func ListRefund(ctx *gin.Context) {
page, size := common.PageSize(ctx)
var refunds []models.PaymentRefund
var total int64
query := common.ApplyKeywordFilter(
ctx,
common.ActiveRecords(impl.DBService.Model(&models.PaymentRefund{})),
&models.PaymentRefund{},
)
if err := query.Count(&total).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
if err := query.Order("created_at desc").Offset((page - 1) * size).Limit(size).Find(&refunds).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
displays, err := buildPaymentRefundDisplays(refunds)
if err != nil {
infra.Response.Error(ctx, err)
return
}
response, err := common.PublicResourceResponse(displays)
if err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{"total": total, "list": response})
}
// GetRefund 返回退款详情,并附加与列表一致的可读关系名称。
func GetRefund(ctx *gin.Context) {
var refund models.PaymentRefund
if err := common.ActiveRecords(impl.DBService).
Where("identity = ?", ctx.Param("identity")).First(&refund).Error; err != nil {
common.RespondRecordError(ctx, err)
return
}
displays, err := buildPaymentRefundDisplays([]models.PaymentRefund{refund})
if err != nil {
infra.Response.Error(ctx, err)
return
}
response, err := common.PublicResourceResponse(displays[0])
if err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, response)
}
// buildPaymentRefundDisplays 批量读取当前页引用,避免退款列表逐行查询。
func buildPaymentRefundDisplays(refunds []models.PaymentRefund) ([]paymentRefundDisplay, error) {
gasorderIdentities := make([]string, 0, len(refunds))
ecOrderIdentities := make([]string, 0, len(refunds))
userIdentities := make([]string, 0, len(refunds))
for _, refund := range refunds {
switch refund.BusinessType {
case "gasorder":
gasorderIdentities = append(gasorderIdentities, refund.BusinessIdentity)
case "ec_order":
ecOrderIdentities = append(ecOrderIdentities, refund.BusinessIdentity)
}
userIdentities = append(userIdentities, refund.UserIdentity)
}
gasorderNames := map[string]string{}
if len(gasorderIdentities) > 0 {
var orders []models.GasorderBasic
if err := common.ActiveRecords(impl.DBService).Select("identity", "order_no").
Where("identity IN ?", gasorderIdentities).Find(&orders).Error; err != nil {
return nil, err
}
for _, order := range orders {
gasorderNames[order.Identity] = order.OrderNo
}
}
ecOrderNames := map[string]string{}
if len(ecOrderIdentities) > 0 {
var orders []models.EcOrder
if err := common.ActiveRecords(impl.DBService).Select("identity", "order_no").
Where("identity IN ?", ecOrderIdentities).Find(&orders).Error; err != nil {
return nil, err
}
for _, order := range orders {
ecOrderNames[order.Identity] = order.OrderNo
}
}
userNames := map[string]string{}
if len(userIdentities) > 0 {
var users []models.UserAccount
if err := common.ActiveRecords(impl.DBService).Select("identity", "name").
Where("identity IN ?", userIdentities).Find(&users).Error; err != nil {
return nil, err
}
for _, user := range users {
userNames[user.Identity] = user.Name
}
}
reviewerNames := map[string]string{}
reviewerIdentities := make([]string, 0, len(refunds))
for _, refund := range refunds {
if refund.ReviewerIdentity != "" {
reviewerIdentities = append(reviewerIdentities, refund.ReviewerIdentity)
}
}
if len(reviewerIdentities) > 0 {
var reviewers []models.PlatformAccount
// 历史审核人即使已经归档也需要保留可读名称,因此不套用活动记录过滤。
if err := impl.DBService.Model(&models.PlatformAccount{}).
Select("identity", "display_name", "username").
Where("identity IN ?", reviewerIdentities).Find(&reviewers).Error; err != nil {
return nil, err
}
for _, reviewer := range reviewers {
reviewerNames[reviewer.Identity] = readableRefundName(
strings.TrimSpace(reviewer.DisplayName),
strings.TrimSpace(reviewer.Username),
)
}
}
productSummaries, err := loadPaymentRefundProductSummaries(refunds)
if err != nil {
return nil, err
}
displays := make([]paymentRefundDisplay, 0, len(refunds))
for _, refund := range refunds {
displays = append(displays, paymentRefundDisplay{
PaymentRefund: refund,
BusinessDisplayName: refundBusinessDisplayName(refund, gasorderNames, ecOrderNames),
UserDisplayName: readableRefundName(userNames[refund.UserIdentity], "用户记录已失效"),
ReviewerDisplayName: refundReviewerDisplayName(refund.ReviewerIdentity, reviewerNames),
RefundProductSummary: productSummaries[refund.ID],
})
}
return displays, nil
}
// refundReviewerDisplayName 区分尚未审核、历史账号失效和正常审核人三种状态。
func refundReviewerDisplayName(identity string, names map[string]string) string {
if strings.TrimSpace(identity) == "" {
return "尚未审核"
}
return readableRefundName(names[identity], "审核人记录已失效")
}
// loadPaymentRefundProductSummaries 批量读取退款明细及原订单项,生成退款商品名称与数量。
func loadPaymentRefundProductSummaries(refunds []models.PaymentRefund) (map[uint64]string, error) {
refundIDs := make([]uint64, 0, len(refunds))
refundTypes := make(map[uint64]string, len(refunds))
for _, refund := range refunds {
refundIDs = append(refundIDs, refund.ID)
refundTypes[refund.ID] = refund.BusinessType
}
var refundItems []models.PaymentRefundItem
if len(refundIDs) > 0 {
if err := impl.DBService.Where("payment_refund_id IN ?", refundIDs).
Order("payment_refund_id asc, id asc").Find(&refundItems).Error; err != nil {
return nil, err
}
}
gasorderItemIdentities := make([]string, 0, len(refundItems))
ecOrderItemIdentities := make([]string, 0, len(refundItems))
for _, item := range refundItems {
if refundTypes[item.PaymentRefundID] == "gasorder" {
gasorderItemIdentities = append(gasorderItemIdentities, item.OrderItemIdentity)
} else if refundTypes[item.PaymentRefundID] == "ec_order" {
ecOrderItemIdentities = append(ecOrderItemIdentities, item.OrderItemIdentity)
}
}
gasorderItems := map[string]models.GasorderItem{}
productInfoIDs := make([]uint64, 0, len(gasorderItemIdentities))
if len(gasorderItemIdentities) > 0 {
var items []models.GasorderItem
if err := common.ActiveRecords(impl.DBService).
Where("identity IN ?", gasorderItemIdentities).Find(&items).Error; err != nil {
return nil, err
}
for _, item := range items {
gasorderItems[item.Identity] = item
productInfoIDs = append(productInfoIDs, item.ProductInfoID)
}
}
productNames := map[uint64]string{}
if len(productInfoIDs) > 0 {
var products []models.ProductInfo
if err := common.ActiveRecords(impl.DBService).Select("id", "name").
Where("id IN ?", productInfoIDs).Find(&products).Error; err != nil {
return nil, err
}
for _, product := range products {
productNames[product.ID] = product.Name
}
}
ecOrderItems := map[string]models.EcOrderItem{}
if len(ecOrderItemIdentities) > 0 {
var items []models.EcOrderItem
if err := common.ActiveRecords(impl.DBService).
Where("identity IN ?", ecOrderItemIdentities).Find(&items).Error; err != nil {
return nil, err
}
for _, item := range items {
ecOrderItems[item.Identity] = item
}
}
labelsByRefund := make(map[uint64][]string, len(refunds))
for _, refundItem := range refundItems {
name := ""
switch refundTypes[refundItem.PaymentRefundID] {
case "gasorder":
item := gasorderItems[refundItem.OrderItemIdentity]
name = strings.TrimSpace(productNames[item.ProductInfoID])
if name == "" {
name = readableRefundName(item.ProductTypeName, item.ProductCode)
}
case "ec_order":
item := ecOrderItems[refundItem.OrderItemIdentity]
var snapshot refundEcProductSnapshot
if json.Unmarshal([]byte(item.ProductSnapshot), &snapshot) == nil {
name = strings.TrimSpace(snapshot.Name)
}
}
labelsByRefund[refundItem.PaymentRefundID] = append(
labelsByRefund[refundItem.PaymentRefundID],
refundProductLabel(name, refundItem.Quantity),
)
}
summaries := make(map[uint64]string, len(refunds))
for _, refund := range refunds {
labels := labelsByRefund[refund.ID]
if len(labels) == 0 {
summaries[refund.ID] = "退款商品信息缺失"
continue
}
summaries[refund.ID] = strings.Join(labels, "、")
}
return summaries, nil
}
// refundProductLabel 统一生成退款商品名称与数量文案。
func refundProductLabel(name string, quantity int) string {
name = strings.TrimSpace(name)
if name == "" {
name = "商品信息缺失"
}
if quantity > 1 {
return name + " × " + strconv.Itoa(quantity)
}
return name
}
// refundBusinessDisplayName 按稳定业务类型选择订单号,未知或失效关系给出明确文案。
func refundBusinessDisplayName(refund models.PaymentRefund, gasorderNames, ecOrderNames map[string]string) string {
switch refund.BusinessType {
case "gasorder":
return readableRefundName(gasorderNames[refund.BusinessIdentity], "订单记录已失效")
case "ec_order":
return readableRefundName(ecOrderNames[refund.BusinessIdentity], "订单记录已失效")
default:
return "未知业务对象"
}
}
// readableRefundName 统一处理退款关联名称缺失场景。
func readableRefundName(value, fallback string) string {
if value == "" {
return fallback
}
return value
}
func review(approve bool) gin.HandlerFunc {
return func(ctx *gin.Context) {
var request struct {