BOM start implementing basic CRUD operations for Bill of Materials and Variant Nodes

This commit is contained in:
2026-08-26 19:27:07 +02:00
parent 8591764ab3
commit adc4179747
4 changed files with 272 additions and 0 deletions
+39
View File
@@ -69,3 +69,42 @@ CREATE TABLE IF NOT EXISTS media (
externalId BIGINT externalId BIGINT
); );
CREATE TABLE IF NOT EXISTS variantNodeContent (
id bigint NOT NULL DEFAULT nextval('global_id_seq'::regclass),
"valueNodeId" bigint,
"productId" bigint,
CONSTRAINT "valueNodeContent_pkey" PRIMARY KEY (id)
)
CREATE TABLE IF NOT EXISTS variantNode
(
id bigint NOT NULL DEFAULT nextval('global_id_seq'::regclass),
label text COLLATE pg_catalog."default",
description text COLLATE pg_catalog."default",
"bomId" bigint,
min integer DEFAULT 1,
max integer DEFAULT 1,
CONSTRAINT "variantNode_pkey" PRIMARY KEY (id)
)
CREATE TABLE IF NOT EXISTS billOfMaterial
(
id bigint NOT NULL DEFAULT nextval('global_id_seq'::regclass),
"productId" bigint,
label text COLLATE pg_catalog."default",
description text COLLATE pg_catalog."default",
"parentBOMId" bigint,
CONSTRAINT "billOfMaterial_pkey" PRIMARY KEY (id)
)
CREATE TABLE IF NOT EXISTS bomContent
(
id bigint NOT NULL DEFAULT nextval('global_id_seq'::regclass),
"bomId" bigint,
"productId" bigint,
min integer DEFAULT 1,
max integer DEFAULT 1,
CONSTRAINT "bomContent_pkey" PRIMARY KEY (id)
)
@@ -0,0 +1,186 @@
package controller
import (
"net/http"
"strconv"
"simplycpq/models"
"simplycpq/services"
"github.com/gin-gonic/gin"
)
type BOMController struct {
bomService *services.BOMService
}
func NewBOMController(b *services.BOMService) *BOMController {
return &BOMController{
bomService: b,
}
}
func (bc *BOMController) CreateBillOfMaterial(c *gin.Context) {
var bom models.BillOfMaterial
err := c.ShouldBindJSON(&bom)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = bc.bomService.CreateBillOfMaterial(&bom)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Status(http.StatusCreated)
}
func (bc *BOMController) GetBOMProductsByBOMId(c *gin.Context) {
bomIdStr := c.Query("bomId")
bomId, err := strconv.ParseInt(bomIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
contents, err := bc.bomService.GetBOMProductsByBOMId(bomId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, contents)
}
func (bc *BOMController) GetBOMVariantNodesByBOMId(c *gin.Context) {
bomIdStr := c.Query("bomId")
bomId, err := strconv.ParseInt(bomIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
variantNodes, err := bc.bomService.GetBOMVariantNodesByBOMId(bomId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, variantNodes)
}
func (bc *BOMController) CreateVariantNode(c *gin.Context) {
var variantNode models.VariantNode
err := c.ShouldBindJSON(&variantNode)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = bc.bomService.CreateVariantNode(&variantNode)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Status(http.StatusCreated)
}
func (bc *BOMController) UpdateVariantNode(c *gin.Context) {
var variantNode models.VariantNode
err := c.ShouldBindJSON(&variantNode)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = bc.bomService.UpdateVariantNode(&variantNode)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Status(http.StatusOK)
}
func (bc *BOMController) DeleteVariantNode(c *gin.Context) {
variantNodeIdStr := c.Query("variantNodeId")
variantNodeId, err := strconv.ParseInt(variantNodeIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = bc.bomService.DeleteVariantNode(variantNodeId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Status(http.StatusOK)
}
func (bc *BOMController) GetVariantNode(c *gin.Context) {
variantNodeIdStr := c.Query("variantNodeId")
variantNodeId, err := strconv.ParseInt(variantNodeIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
variantNode, err := bc.bomService.GetVariantNodeById(variantNodeId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, variantNode)
}
func (bc *BOMController) GetVariantNodeProductsByVariantNodeId(c *gin.Context) {
variantNodeIdStr := c.Query("variantNodeId")
variantNodeId, err := strconv.ParseInt(variantNodeIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
products, err := bc.bomService.GetVariantNodeProductsByVariantNodeId(variantNodeId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, products)
}
func (bc *BOMController) UpdateBillOfMaterial(c *gin.Context) {
var bom models.BillOfMaterial
err := c.ShouldBindJSON(&bom)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = bc.bomService.UpdateBillOfMaterial(&bom)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Status(http.StatusOK)
}
func (bc *BOMController) DeleteBillOfMaterial(c *gin.Context) {
bomIdStr := c.Query("id")
bomId, err := strconv.ParseInt(bomIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = bc.bomService.DeleteBillOfMaterial(bomId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Status(http.StatusOK)
}
func (bc *BOMController) GetBillOfMaterial(c *gin.Context) {
bomIdStr := c.Query("id")
bomId, err := strconv.ParseInt(bomIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
bom, err := bc.bomService.GetBillOfMaterial(bomId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, bom)
}
+30
View File
@@ -0,0 +1,30 @@
package models
type BillOfMaterial struct {
ID int64 `json:"id,omitempty"`
ProductID int64 `json:"productId"`
Label string `json:"label"`
Description string `json:"description"`
ParentBOMID int64 `json:"parentBOMId,omitempty"`
}
type BOMContent struct {
ID int64 `json:"id,omitempty"`
BOMID int64 `json:"bomId"`
ProductID int64 `json:"productId"`
Min int `json:"min,omitempty"`
Max int `json:"max,omitempty"`
}
type VariantNode struct {
ID int64 `json:"id,omitempty"`
Label string `json:"label"`
Description string `json:"description"`
BOMID int64 `json:"bomId,omitempty"`
}
type VariantNodeContent struct {
ID int64 `json:"id,omitempty"`
VariantNodeID int64 `json:"variantNodeId"`
ProductID int64 `json:"productId"`
}
+17
View File
@@ -21,6 +21,7 @@ type HttpServer struct {
valueController *controller.ValueController valueController *controller.ValueController
productGroupController *controller.ProductGroupController productGroupController *controller.ProductGroupController
productController *controller.ProductController productController *controller.ProductController
bomController *controller.BOMController
} }
func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer { func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
@@ -30,17 +31,20 @@ func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
productGroupRepository := repositories.NewProductGroupRepository(dbHandler, valueRepository) productGroupRepository := repositories.NewProductGroupRepository(dbHandler, valueRepository)
productRepository := repositories.NewProductRepository(dbHandler, productGroupRepository, valueRepository) productRepository := repositories.NewProductRepository(dbHandler, productGroupRepository, valueRepository)
importRepository := repositories.NewImportRepository(dbHandler, productGroupRepository, productRepository, valueRepository) importRepository := repositories.NewImportRepository(dbHandler, productGroupRepository, productRepository, valueRepository)
bomRepository := repositories.NewBOMRepository(dbHandler, productRepository)
// service initialisation: // service initialisation:
valueService := services.NewValueService(valueRepository) valueService := services.NewValueService(valueRepository)
productGroupService := services.NewProductGroupService(productGroupRepository) productGroupService := services.NewProductGroupService(productGroupRepository)
productService := services.NewProductService(productRepository) productService := services.NewProductService(productRepository)
importService := services.NewImportService(importRepository) importService := services.NewImportService(importRepository)
bomService := services.NewBOMService(bomRepository)
// controller initialisation: // controller initialisation:
valueController := controller.NewValueController(valueService) valueController := controller.NewValueController(valueService)
productGroupController := controller.NewProductGroupController(productGroupService, valueService) productGroupController := controller.NewProductGroupController(productGroupService, valueService)
productController := controller.NewProductController(productService, productGroupService, valueService) productController := controller.NewProductController(productService, productGroupService, valueService)
bomController := controller.NewBOMController(bomService)
importController := controller.NewImportController(importService) importController := controller.NewImportController(importService)
// Service API // Service API
@@ -92,6 +96,19 @@ func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
router.POST("/addPropertyToProductId/:productId", productController.AddPropertyToProductId) // add Property to Product by ID router.POST("/addPropertyToProductId/:productId", productController.AddPropertyToProductId) // add Property to Product by ID
router.DELETE("/deletePropertyFromProductId/:productId", productController.DeletePropertyFromProductId) // delete Property from Product by ID router.DELETE("/deletePropertyFromProductId/:productId", productController.DeletePropertyFromProductId) // delete Property from Product by ID
// BOM centric routing
router.POST("/createBillOfMaterial", bomController.CreateBillOfMaterial)
router.PUT("/updateBillOfMaterial", bomController.UpdateBillOfMaterial)
router.DELETE("/deleteBillOfMaterial/:id", bomController.DeleteBillOfMaterial)
router.GET("/getBillOfMaterial/:id", bomController.GetBillOfMaterial)
router.GET("/getBOMProductsByBOMId/:bomId", bomController.GetBOMProductsByBOMId) // get all BOMContents by BOM ID
router.GET("/getBOMVariantNodesByBOMId/:bomId", bomController.GetBOMVariantNodesByBOMId) // get all VariantNodes by BOM ID
router.POST("/createVariantNode/:bomId", bomController.CreateVariantNode)
router.PUT("/updateVariantNode", bomController.UpdateVariantNode)
router.DELETE("/deleteVariantNode/:id", bomController.DeleteVariantNode)
router.GET("/getVariantNode/:id", bomController.GetVariantNode)
router.GET("/getVariantNodeProductsByVariantNodeId/:variantNodeId", bomController.GetVariantNodeProductsByVariantNodeId)
// Import functionality // Import functionality
router.POST("/importPropertyTypeGroups", importController.ImportPropertyTypeGroups) // import PropertyTypeGroups router.POST("/importPropertyTypeGroups", importController.ImportPropertyTypeGroups) // import PropertyTypeGroups
router.POST("/importProductGroups", importController.ImportProductGroups) // import ProductGroups router.POST("/importProductGroups", importController.ImportProductGroups) // import ProductGroups