Files
goauto/server/app/goauto/sybimport/handler.go
T

214 lines
5.6 KiB
Go

package sybimport
import (
"encoding/json"
"errors"
"io"
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/go-admin-team/go-admin-core/sdk/pkg"
"gorm.io/gorm"
)
type Handler struct {
DB *gorm.DB
// internalErrorLogger is only overridden by tests. Production requests use
// the request-scoped go-admin logger so the stage and safe cause stay tied
// to the request without putting them in the HTTP response.
internalErrorLogger func(stage, safeCause string)
}
func (handler Handler) logInternalFailure(c *gin.Context, stage string, err error) {
safeCause := sanitizeInternalError(err)
if handler.internalErrorLogger != nil {
handler.internalErrorLogger(stage, safeCause)
return
}
api.GetRequestLogger(c).Errorf("SYB import failed before task creation: stage=%s cause=%s", stage, safeCause)
}
func (handler Handler) List(c *gin.Context) {
var shopIDs []uint64
if values, present := c.Request.URL.Query()["shopIds"]; present {
if len(values) == 0 || len(values) > 50 {
writeError(c, invalidRequest("shopIds 数量必须为 1 到 50 个"))
return
}
shopIDs = make([]uint64, 0, len(values))
for _, value := range values {
id, err := strconv.ParseUint(value, 10, 64)
if err != nil || id == 0 {
writeError(c, invalidRequest("shopIds 必须是有效的店铺 ID"))
return
}
shopIDs = append(shopIDs, id)
}
}
page, err := queryInt(c.Query("page"), 1)
if err != nil {
writeError(c, invalidRequest("page 必须是正整数"))
return
}
pageSize, err := queryInt(c.Query("pageSize"), 20)
if err != nil {
writeError(c, invalidRequest("pageSize 必须是正整数"))
return
}
service, ok := handler.service(c)
if !ok {
return
}
response, err := service.List(c.Request.Context(), ListRequest{
Page: page, PageSize: pageSize, ShopName: c.Query("shopName"), ShopIDs: shopIDs, OrderCodes: []string{c.Query("orderCodes")}, ParseStatus: strings.TrimSpace(c.Query("parseStatus")), ProcessStage: strings.TrimSpace(c.Query("processStage")), CreatedFrom: strings.TrimSpace(c.Query("createdFrom")), CreatedTo: strings.TrimSpace(c.Query("createdTo")), PurchaseType: strings.TrimSpace(c.Query("purchaseType")),
})
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": response})
}
func (handler Handler) Detail(c *gin.Context) {
id, ok := handler.pathID(c)
if !ok {
return
}
service, ok := handler.service(c)
if !ok {
return
}
record, err := service.Detail(c.Request.Context(), id)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"item": record}})
}
func (handler Handler) Reparse(c *gin.Context) {
id, ok := handler.pathID(c)
if !ok {
return
}
var request ReparseRequest
if err := decodeJSON(c, &request); err != nil {
writeError(c, invalidRequest("请求 JSON 无效"))
return
}
service, ok := handler.service(c)
if !ok {
return
}
outcome, err := service.Reparse(c.Request.Context(), id, request)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": outcome})
}
func (handler Handler) ReparseBatch(c *gin.Context) {
var request ReparseBatchRequest
if err := decodeJSON(c, &request); err != nil {
writeError(c, invalidRequest("请求 JSON 无效"))
return
}
service, ok := handler.service(c)
if !ok {
return
}
results, err := service.ReparseBatch(c.Request.Context(), request)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"results": results}})
}
func (handler Handler) ManualCorrect(c *gin.Context) {
id, ok := handler.pathID(c)
if !ok {
return
}
var request ManualCorrectRequest
if err := decodeJSON(c, &request); err != nil {
writeError(c, invalidRequest("请求 JSON 无效"))
return
}
service, ok := handler.service(c)
if !ok {
return
}
record, err := service.ManualCorrect(c.Request.Context(), id, request)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"item": record}})
}
func (handler Handler) pathID(c *gin.Context) (uint64, bool) {
id, err := strconv.ParseUint(c.Param("productId"), 10, 64)
if err != nil || id == 0 {
writeError(c, invalidRequest("productId 无效"))
return 0, false
}
return id, true
}
func (handler Handler) service(c *gin.Context) (*Service, bool) {
db := handler.DB
var err error
if db == nil {
db, err = pkg.GetOrm(c)
}
if err != nil {
writeError(c, internalError(err))
return nil, false
}
return NewService(db), true
}
func decodeJSON(c *gin.Context, request any) error {
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 1<<20)
decoder := json.NewDecoder(c.Request.Body)
decoder.DisallowUnknownFields()
if err := decoder.Decode(request); err != nil {
return err
}
if err := decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
return errors.New("one object required")
}
return nil
}
func queryInt(value string, fallback int) (int, error) {
if strings.TrimSpace(value) == "" {
return fallback, nil
}
parsed, err := strconv.Atoi(value)
if err != nil || parsed < 1 {
return 0, errors.New("invalid integer")
}
return parsed, nil
}
func writeError(c *gin.Context, err error) {
var target *ServiceError
if !errors.As(err, &target) {
target = internalError(err).(*ServiceError)
}
status := http.StatusInternalServerError
switch target.Code {
case CodeInvalidRequest:
status = http.StatusUnprocessableEntity
case CodeNotFound:
status = http.StatusNotFound
}
c.JSON(status, gin.H{"code": target.Code, "message": target.Message})
}