修复财务支付记录展示
This commit is contained in:
@@ -5,15 +5,152 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// finPaymentProductSnapshot 是商城下单时固化的商品成交快照最小结构。
|
||||
type finPaymentProductSnapshot struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// ListFinPayment 返回财务支付记录列表,并批量附加成交商品摘要。
|
||||
func ListFinPayment(ctx *gin.Context) {
|
||||
page, size := common.PageSize(ctx)
|
||||
var payments []models.FinPayment
|
||||
var total int64
|
||||
query := common.ApplyKeywordFilter(
|
||||
ctx,
|
||||
common.ActiveRecords(impl.DBService.Model(&models.FinPayment{})),
|
||||
&models.FinPayment{},
|
||||
)
|
||||
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(&payments).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
summaries, err := loadFinPaymentProductSummaries(payments)
|
||||
if err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
response, err := common.PublicResourceResponse(payments)
|
||||
if err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
rows, ok := response.([]any)
|
||||
if !ok || len(rows) != len(payments) {
|
||||
infra.Response.Error(ctx, errors.New("invalid finance payment list response"))
|
||||
return
|
||||
}
|
||||
for index, payment := range payments {
|
||||
row, valid := rows[index].(map[string]any)
|
||||
if !valid {
|
||||
infra.Response.Error(ctx, errors.New("invalid finance payment row response"))
|
||||
return
|
||||
}
|
||||
row["product_summary"] = summaries[payment.EcOrderID]
|
||||
}
|
||||
infra.Response.Success(ctx, gin.H{
|
||||
"total": total,
|
||||
"list": common.ProtectPreciseLocation(ctx, &models.FinPayment{}, response),
|
||||
})
|
||||
}
|
||||
|
||||
// loadFinPaymentProductSummaries 一次查询当前页全部订单明细,避免列表逐行查询。
|
||||
func loadFinPaymentProductSummaries(payments []models.FinPayment) (map[uint64]string, error) {
|
||||
orderIDs := make([]uint64, 0, len(payments))
|
||||
seen := make(map[uint64]struct{}, len(payments))
|
||||
for _, payment := range payments {
|
||||
if _, exists := seen[payment.EcOrderID]; exists {
|
||||
continue
|
||||
}
|
||||
seen[payment.EcOrderID] = struct{}{}
|
||||
orderIDs = append(orderIDs, payment.EcOrderID)
|
||||
}
|
||||
itemsByOrder := make(map[uint64][]models.EcOrderItem, len(orderIDs))
|
||||
if len(orderIDs) > 0 {
|
||||
var items []models.EcOrderItem
|
||||
if err := common.ActiveRecords(impl.DBService).
|
||||
Where("ec_order_id IN ?", orderIDs).
|
||||
Order("ec_order_id asc, id asc").Find(&items).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range items {
|
||||
itemsByOrder[item.EcOrderID] = append(itemsByOrder[item.EcOrderID], item)
|
||||
}
|
||||
}
|
||||
summaries := make(map[uint64]string, len(orderIDs))
|
||||
for _, orderID := range orderIDs {
|
||||
summaries[orderID] = finPaymentProductSummary(itemsByOrder[orderID])
|
||||
}
|
||||
return summaries, nil
|
||||
}
|
||||
|
||||
// GetFinPayment 返回支付详情,并从订单商品快照生成财务可读的商品摘要。
|
||||
func GetFinPayment(ctx *gin.Context) {
|
||||
var payment models.FinPayment
|
||||
if err := common.ActiveRecords(impl.DBService).
|
||||
Where("identity = ?", ctx.Param("identity")).First(&payment).Error; err != nil {
|
||||
common.RespondRecordError(ctx, err)
|
||||
return
|
||||
}
|
||||
var items []models.EcOrderItem
|
||||
if err := common.ActiveRecords(impl.DBService).
|
||||
Where("ec_order_id = ?", payment.EcOrderID).
|
||||
Order("id asc").Find(&items).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
response, err := common.PublicResourceResponse(payment)
|
||||
if err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
data, ok := response.(map[string]any)
|
||||
if !ok {
|
||||
infra.Response.Error(ctx, errors.New("invalid finance payment response"))
|
||||
return
|
||||
}
|
||||
data["product_summary"] = finPaymentProductSummary(items)
|
||||
infra.Response.Success(ctx, data)
|
||||
}
|
||||
|
||||
// finPaymentProductSummary 优先使用不可变成交快照,避免商品改名后财务详情发生漂移。
|
||||
func finPaymentProductSummary(items []models.EcOrderItem) string {
|
||||
summaries := make([]string, 0, len(items))
|
||||
for _, item := range items {
|
||||
var snapshot finPaymentProductSnapshot
|
||||
if err := json.Unmarshal([]byte(item.ProductSnapshot), &snapshot); err != nil {
|
||||
continue
|
||||
}
|
||||
name := strings.TrimSpace(snapshot.Name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if item.Quantity > 1 {
|
||||
name += " × " + strconv.Itoa(item.Quantity)
|
||||
}
|
||||
summaries = append(summaries, name)
|
||||
}
|
||||
if len(summaries) == 0 {
|
||||
return "商品信息缺失"
|
||||
}
|
||||
return strings.Join(summaries, "、")
|
||||
}
|
||||
|
||||
func FinSettlementHandlers() (gin.HandlerFunc, gin.HandlerFunc, gin.HandlerFunc, gin.HandlerFunc) {
|
||||
fields := []string{"settlement_no", "subject_type", "subject_id", "period_start", "period_end"}
|
||||
return func(ctx *gin.Context) { common.ListResource(ctx, &models.FinSettlement{}) },
|
||||
|
||||
Reference in New Issue
Block a user