fix: resolve platform relation identities
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@@ -33,6 +35,60 @@ func ResourceHandlers(model any, createFields, updateFields []string, relations
|
||||
func(ctx *gin.Context) { updateResource(ctx, model, updateFields, relations) }
|
||||
}
|
||||
|
||||
// FinSettlementHandlers accepts a public subject_identity and derives the
|
||||
// polymorphic storage key from its declared subject_type.
|
||||
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) { listResource(ctx, &models.FinSettlement{}) },
|
||||
func(ctx *gin.Context) {
|
||||
if err := rewriteSettlementSubject(ctx); err != nil {
|
||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||
return
|
||||
}
|
||||
createResource(ctx, &models.FinSettlement{}, fields, nil)
|
||||
},
|
||||
func(ctx *gin.Context) { getResource(ctx, &models.FinSettlement{}) },
|
||||
func(ctx *gin.Context) {
|
||||
if err := rewriteSettlementSubject(ctx); err != nil {
|
||||
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
|
||||
return
|
||||
}
|
||||
updateResource(ctx, &models.FinSettlement{}, fields, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func rewriteSettlementSubject(ctx *gin.Context) error {
|
||||
var input map[string]any
|
||||
if err := ctx.ShouldBindJSON(&input); err != nil {
|
||||
return err
|
||||
}
|
||||
subjectType, _ := input["subject_type"].(string)
|
||||
identity, _ := input["subject_identity"].(string)
|
||||
var model any
|
||||
switch subjectType {
|
||||
case "gas", "gas_basic":
|
||||
model = &models.GasBasic{}
|
||||
case "delivery", "delivery_basic":
|
||||
model = &models.DeliveryBasic{}
|
||||
case "staff", "staff_account":
|
||||
model = &models.StaffAccount{}
|
||||
default:
|
||||
return errors.New("invalid settlement subject")
|
||||
}
|
||||
id, err := resolveIdentityID(model, identity, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delete(input, "subject_identity")
|
||||
input["subject_id"] = id
|
||||
encoded, err := json.Marshal(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Request.Body = io.NopCloser(bytes.NewReader(encoded))
|
||||
return nil
|
||||
}
|
||||
|
||||
func listResource(ctx *gin.Context, model any) {
|
||||
page, size := pageSize(ctx)
|
||||
list := reflect.New(reflect.SliceOf(reflect.TypeOf(model).Elem()))
|
||||
@@ -126,15 +182,32 @@ func resolveResourceRelations(input map[string]any, allowedFields []string, rela
|
||||
if !ok || strings.TrimSpace(identity) == "" {
|
||||
return nil, errors.New("invalid relation identity")
|
||||
}
|
||||
var related struct{ ID uint64 }
|
||||
if err := impl.DBService.Model(relation.Model).Select("id").Where("identity = ?", identity).First(&related).Error; err != nil {
|
||||
id, err := resolveIdentityID(relation.Model, identity, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values[relation.Column] = related.ID
|
||||
values[relation.Column] = id
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// resolveIdentityID is the only boundary that converts a public identity to a
|
||||
// persistence-only numeric key. Callers must never bind a client supplied ID.
|
||||
func resolveIdentityID(model any, identity string, required bool) (uint64, error) {
|
||||
identity = strings.TrimSpace(identity)
|
||||
if identity == "" {
|
||||
if required {
|
||||
return 0, errors.New("missing required relation")
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
var related struct{ ID uint64 }
|
||||
if err := impl.DBService.Model(model).Select("id").Where("identity = ?", identity).First(&related).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return related.ID, nil
|
||||
}
|
||||
|
||||
func relationColumns(relations []ResourceRelation) []string {
|
||||
columns := make([]string, 0, len(relations))
|
||||
for _, relation := range relations {
|
||||
@@ -266,3 +339,75 @@ func GetDeliveryTrack(ctx *gin.Context) {
|
||||
}
|
||||
infra.Response.Success(ctx, resourceResponse(gin.H{"track": track, "points": points}))
|
||||
}
|
||||
|
||||
type ecCategoryView struct {
|
||||
Identity string `json:"identity"`
|
||||
ParentIdentity string `json:"parent_identity,omitempty"`
|
||||
Name string `json:"name"`
|
||||
SortNo int `json:"sort_no"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func ecCategoryViews(list []models.EcCategory) ([]ecCategoryView, error) {
|
||||
parents := make(map[uint64]string)
|
||||
for _, item := range list {
|
||||
if item.ParentID != 0 {
|
||||
parents[item.ParentID] = ""
|
||||
}
|
||||
}
|
||||
if len(parents) > 0 {
|
||||
var rows []struct {
|
||||
ID uint64
|
||||
Identity string
|
||||
}
|
||||
ids := make([]uint64, 0, len(parents))
|
||||
for id := range parents {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
if err := impl.DBService.Model(&models.EcCategory{}).Select("id", "identity").Where("id IN ?", ids).Find(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, row := range rows {
|
||||
parents[row.ID] = row.Identity
|
||||
}
|
||||
}
|
||||
views := make([]ecCategoryView, 0, len(list))
|
||||
for _, item := range list {
|
||||
views = append(views, ecCategoryView{Identity: item.Identity, ParentIdentity: parents[item.ParentID], Name: item.Name, SortNo: item.SortNo, Status: item.Status})
|
||||
}
|
||||
return views, nil
|
||||
}
|
||||
|
||||
func ListEcCategory(ctx *gin.Context) {
|
||||
page, size := pageSize(ctx)
|
||||
var list []models.EcCategory
|
||||
var total int64
|
||||
if err := impl.DBService.Model(&models.EcCategory{}).Count(&total).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
if err := impl.DBService.Order("sort_no asc, id asc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
views, err := ecCategoryViews(list)
|
||||
if err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, gin.H{"total": total, "list": views})
|
||||
}
|
||||
|
||||
func GetEcCategory(ctx *gin.Context) {
|
||||
var category models.EcCategory
|
||||
if err := impl.DBService.Where("identity = ?", ctx.Param("identity")).First(&category).Error; err != nil {
|
||||
respondRecordError(ctx, err)
|
||||
return
|
||||
}
|
||||
views, err := ecCategoryViews([]models.EcCategory{category})
|
||||
if err != nil {
|
||||
infra.Response.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
infra.Response.Success(ctx, views[0])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user