feat: product.
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"hr_receiver/config"
|
||||
"hr_receiver/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ProductDefinitionAdminController struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
type productDefinitionPayload struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Category string `json:"category"`
|
||||
Description string `json:"description"`
|
||||
ParameterSchema string `json:"parameterSchema"`
|
||||
TrackSerialNumber bool `json:"trackSerialNumber"`
|
||||
IsActive bool `json:"isActive"`
|
||||
Sort int `json:"sort"`
|
||||
}
|
||||
|
||||
func NewProductDefinitionAdminController() *ProductDefinitionAdminController {
|
||||
return &ProductDefinitionAdminController{DB: config.DB}
|
||||
}
|
||||
|
||||
func (pc *ProductDefinitionAdminController) List(c *gin.Context) {
|
||||
var items []models.ProductDefinition
|
||||
query := pc.DB.Model(&models.ProductDefinition{}).Order("sort ASC, id ASC")
|
||||
|
||||
if keyword := strings.TrimSpace(c.Query("keyword")); keyword != "" {
|
||||
likeValue := "%" + keyword + "%"
|
||||
query = query.Where("code LIKE ? OR name LIKE ? OR description LIKE ?", likeValue, likeValue, likeValue)
|
||||
}
|
||||
if category := strings.TrimSpace(c.Query("category")); category != "" {
|
||||
query = query.Where("category = ?", strings.ToLower(category))
|
||||
}
|
||||
if isActiveStr := strings.TrimSpace(c.Query("isActive")); isActiveStr != "" {
|
||||
isActive, err := strconv.ParseBool(isActiveStr)
|
||||
if err != nil {
|
||||
writeError(c, http.StatusBadRequest, "invalid isActive")
|
||||
return
|
||||
}
|
||||
query = query.Where("is_active = ?", isActive)
|
||||
}
|
||||
|
||||
if err := query.Find(&items).Error; err != nil {
|
||||
writeError(c, http.StatusInternalServerError, "failed to query product definitions")
|
||||
return
|
||||
}
|
||||
writeSuccess(c, http.StatusOK, "query success", items)
|
||||
}
|
||||
|
||||
func (pc *ProductDefinitionAdminController) Create(c *gin.Context) {
|
||||
var payload productDefinitionPayload
|
||||
if err := c.ShouldBindJSON(&payload); err != nil {
|
||||
writeError(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if err := validateProductDefinitionPayload(payload); err != nil {
|
||||
writeError(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
record := models.ProductDefinition{
|
||||
Code: payload.Code,
|
||||
Name: payload.Name,
|
||||
Category: payload.Category,
|
||||
Description: payload.Description,
|
||||
ParameterSchema: payload.ParameterSchema,
|
||||
TrackSerialNumber: payload.TrackSerialNumber,
|
||||
IsActive: payload.IsActive,
|
||||
Sort: payload.Sort,
|
||||
}
|
||||
if err := pc.DB.Create(&record).Error; err != nil {
|
||||
writeProductDefinitionDBError(c, err)
|
||||
return
|
||||
}
|
||||
writeSuccess(c, http.StatusCreated, "create success", record)
|
||||
}
|
||||
|
||||
func (pc *ProductDefinitionAdminController) Update(c *gin.Context) {
|
||||
record, err := pc.findByID(c.Param("id"))
|
||||
if err != nil {
|
||||
respondProductDefinitionLookupError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
var payload productDefinitionPayload
|
||||
if err := c.ShouldBindJSON(&payload); err != nil {
|
||||
writeError(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if err := validateProductDefinitionPayload(payload); err != nil {
|
||||
writeError(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
record.Code = payload.Code
|
||||
record.Name = payload.Name
|
||||
record.Category = payload.Category
|
||||
record.Description = payload.Description
|
||||
record.ParameterSchema = payload.ParameterSchema
|
||||
record.TrackSerialNumber = payload.TrackSerialNumber
|
||||
record.IsActive = payload.IsActive
|
||||
record.Sort = payload.Sort
|
||||
|
||||
if err := pc.DB.Save(&record).Error; err != nil {
|
||||
writeProductDefinitionDBError(c, err)
|
||||
return
|
||||
}
|
||||
writeSuccess(c, http.StatusOK, "update success", record)
|
||||
}
|
||||
|
||||
func (pc *ProductDefinitionAdminController) Delete(c *gin.Context) {
|
||||
record, err := pc.findByID(c.Param("id"))
|
||||
if err != nil {
|
||||
respondProductDefinitionLookupError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
var inventoryCount int64
|
||||
if err := pc.DB.Model(&models.ProductInventory{}).Where("product_code = ?", record.Code).Count(&inventoryCount).Error; err != nil {
|
||||
writeError(c, http.StatusInternalServerError, "failed to check inventory references")
|
||||
return
|
||||
}
|
||||
if inventoryCount > 0 {
|
||||
writeError(c, http.StatusConflict, "current product definition is referenced by inventory")
|
||||
return
|
||||
}
|
||||
|
||||
var templateCount int64
|
||||
if err := pc.DB.Model(&models.ProjectProductTemplate{}).Where("product_code = ?", record.Code).Count(&templateCount).Error; err != nil {
|
||||
writeError(c, http.StatusInternalServerError, "failed to check project template references")
|
||||
return
|
||||
}
|
||||
if templateCount > 0 {
|
||||
writeError(c, http.StatusConflict, "current product definition is referenced by project templates")
|
||||
return
|
||||
}
|
||||
|
||||
if err := pc.DB.Delete(&record).Error; err != nil {
|
||||
writeError(c, http.StatusInternalServerError, "failed to delete product definition")
|
||||
return
|
||||
}
|
||||
writeSuccess(c, http.StatusOK, "delete success", nil)
|
||||
}
|
||||
|
||||
func (pc *ProductDefinitionAdminController) findByID(id string) (models.ProductDefinition, error) {
|
||||
var record models.ProductDefinition
|
||||
numericID, err := strconv.ParseUint(strings.TrimSpace(id), 10, 64)
|
||||
if err != nil {
|
||||
return record, gorm.ErrRecordNotFound
|
||||
}
|
||||
if err := pc.DB.First(&record, numericID).Error; err != nil {
|
||||
return record, err
|
||||
}
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func validateProductDefinitionPayload(payload productDefinitionPayload) error {
|
||||
if strings.TrimSpace(payload.Code) == "" {
|
||||
return errors.New("code is required")
|
||||
}
|
||||
if strings.TrimSpace(payload.Name) == "" {
|
||||
return errors.New("name is required")
|
||||
}
|
||||
if strings.TrimSpace(payload.Category) == "" {
|
||||
return errors.New("category is required")
|
||||
}
|
||||
if strings.TrimSpace(payload.ParameterSchema) != "" && !json.Valid([]byte(strings.TrimSpace(payload.ParameterSchema))) {
|
||||
return errors.New("parameterSchema must be valid JSON")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func respondProductDefinitionLookupError(c *gin.Context, err error) {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
writeError(c, http.StatusNotFound, "product definition not found")
|
||||
return
|
||||
}
|
||||
writeError(c, http.StatusInternalServerError, "failed to query product definition")
|
||||
}
|
||||
|
||||
func writeProductDefinitionDBError(c *gin.Context, err error) {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "unique") {
|
||||
writeError(c, http.StatusConflict, "product code already exists")
|
||||
return
|
||||
}
|
||||
writeError(c, http.StatusInternalServerError, "failed to persist product definition")
|
||||
}
|
||||
Reference in New Issue
Block a user