diff --git a/buildtime/server/README.md b/buildtime/server/README.md index 6abbf9ed4..7bc9bbe10 100644 --- a/buildtime/server/README.md +++ b/buildtime/server/README.md @@ -72,7 +72,7 @@ CREATE TABLE tabelle_a ( - updateValueFromValueId - - add + - addValueToPropertyType - Produkte haben zusätzlich zur ID, Label und Beschreibung noch eine externalId. @@ -107,7 +107,7 @@ CREATE TABLE IF NOT EXISTS values ( id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'), Label TEXT, description TEXT, - propertyId BIGINT + propertyGroupId BIGINT ); -- Property Table @@ -163,11 +163,8 @@ CREATE TABLE IF NOT EXISTS media ( mediaType TEXT, externalId BIGINT ); - ``` - - ## Open Aufsetzen des Source Codes: ```` @@ -218,4 +215,47 @@ go get github.com/gin-contrib/cors ## Server API -Die Server-API baut auf HTTP und auf REST auf. Antworten werden im JSON Format gesendet,ebenso, wie neu anzulegende Daten oder zu aktualisierende Daten. \ No newline at end of file +Die Server-API baut auf HTTP und auf REST auf. Antworten werden im JSON Format gesendet,ebenso, wie neu anzulegende Daten oder zu aktualisierende Daten. + +Generell werden Daten im JSON Format ausgetauscht. Z.B. wird ein *Value* Objekt in From von *application/json Daten* übergeben: + +```gettext +put: http://server:port/updatePropertyType +``` + +benötigt folgende Struktur im Anfragekörper: + +```json +{ + "id": 1000003, + "label": "Colour", + "description": "System wide colors", + "propertyTypeGroupId": 100002 +} +``` + +und liefert als Ergebnis (wenn kein Fehler auftritt): + +```json +{ + "data": { + "id": 1000003, + "label": "Colour", + "description": "System wide colors", + "propertyTypeGroupId": 100002 + }, + "message": "PropertyType updated" +} +``` + +Wenn Daten zurückkommen, so wie hier im Beispiel, dann werden sie im *"data"* Tag geschrieben. Meistens kommt auch noch eine Nachricht mit, die in *"message"* steht. + + Im Falle eines Fehler kommt eine entsprechende Nachricht zurück (z.B. wenn es keinen PropertyType mit der entsprechenden *ID* gibt): + +```json +{ + "error": "sql: no rows in result set" +} +``` + +### Value und Property Funktionen \ No newline at end of file diff --git a/buildtime/server/controller/productController.go b/buildtime/server/controller/productController.go new file mode 100644 index 000000000..023c1a217 --- /dev/null +++ b/buildtime/server/controller/productController.go @@ -0,0 +1,142 @@ +package controller + +import ( + "net/http" + "simplycpq/models" + "simplycpq/services" + "strconv" + + "github.com/gin-gonic/gin" +) + +type ProductController struct { + productService *services.ProductService + productGroupService *services.ProductGroupService + valueService *services.ValueService +} + +func NewProductController(productService *services.ProductService, productGroupService *services.ProductGroupService, valueService *services.ValueService) *ProductController { + return &ProductController{ + productService: productService, + productGroupService: productGroupService, + valueService: valueService, + } +} + +func (pc *ProductController) CreateProduct(c *gin.Context) { + var product models.Product + if err := c.ShouldBindJSON(&product); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + createdProduct, err := pc.productService.CreateProduct(&product) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "product created successfully", "data": createdProduct}) +} + +func (pc *ProductController) UpdateProduct(c *gin.Context) { + var product models.Product + if err := c.ShouldBindJSON(&product); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + if err := pc.productService.UpdateProduct(&product); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "product updated successfully"}) +} + +func (pc *ProductController) DeleteProduct(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"}) + return + } + if err := pc.productService.DeleteProduct(id); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "product deleted successfully"}) +} + +func (pc *ProductController) GetProduct(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"}) + return + } + product, err := pc.productService.GetProductById(id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "product retrieved successfully", "product": product}) +} + +func (pc *ProductController) GetProductsByGroupId(c *gin.Context) { + groupId, err := strconv.Atoi(c.Param("groupId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid group id"}) + return + } + products, err := pc.productService.GetProductsByGroupId(groupId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "products retrieved successfully", "groupId": groupId, "products": products}) +} + +func (pc *ProductController) AddPropertyToProductId(c *gin.Context) { + productId, err := strconv.Atoi(c.Param("productId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"}) + return + } + propertyId, err := strconv.Atoi(c.Param("propertyId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid property id"}) + return + } + if err := pc.productService.AddPropertyToProduct(productId, propertyId); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "property added to product successfully", "productId": productId, "propertyId": propertyId}) +} + +func (pc *ProductController) DeletePropertyFromProductId(c *gin.Context) { + productId, err := strconv.Atoi(c.Param("productId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"}) + return + } + propertyId, err := strconv.Atoi(c.Param("propertyId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid property id"}) + return + } + if err := pc.productService.DeletePropertyFromProduct(productId, propertyId); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "property deleted from product successfully", "productId": productId, "propertyId": propertyId}) +} + +func (pc *ProductController) GetPropertiesFromProductId(c *gin.Context) { + productId, err := strconv.Atoi(c.Param("productId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"}) + return + } + properties, err := pc.productService.GetPropertiesFromProduct(productId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"status": "properties retrieved from product successfully", "productId": productId, "properties": properties}) +} diff --git a/buildtime/server/controller/productGroupController.go b/buildtime/server/controller/productGroupController.go new file mode 100644 index 000000000..f7f6221e6 --- /dev/null +++ b/buildtime/server/controller/productGroupController.go @@ -0,0 +1,162 @@ +package controller + +import ( + "net/http" + + "simplycpq/models" + "simplycpq/services" + + "strconv" + + "github.com/gin-gonic/gin" +) + +type ProductGroupController struct { + productGroupService *services.ProductGroupService + valueService *services.ValueService +} + +func NewProductGroupController(productGroupService *services.ProductGroupService, valueService *services.ValueService) *ProductGroupController { + return &ProductGroupController{ + productGroupService: productGroupService, + valueService: valueService, + } +} + +func (pgc *ProductGroupController) CreateProductGroup(c *gin.Context) { + var productGroup models.ProductGroup + if err := c.ShouldBindJSON(&productGroup); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + createdProductGroup, err := pgc.productGroupService.CreateProductGroup(&productGroup) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, createdProductGroup) +} + +func (pgc *ProductGroupController) UpdateProductGroup(c *gin.Context) { + var productGroup models.ProductGroup + if err := c.ShouldBindJSON(&productGroup); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + updatedProductGroup, err := pgc.productGroupService.UpdateProductGroup(&productGroup) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, updatedProductGroup) +} + +func (pgc *ProductGroupController) DeleteProductGroup(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"}) + return + } + err = pgc.productGroupService.DeleteProductGroup(id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "ProductGroup deleted successfully"}) +} + +func (pgc *ProductGroupController) GetProductGroup(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"}) + return + } + productGroup, err := pgc.productGroupService.GetProductGroup(id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, productGroup) +} + +func (pgc *ProductGroupController) GetProductGroupsByParentId(c *gin.Context) { + parentId, err := strconv.Atoi(c.Param("parentId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid parent ID"}) + return + } + productGroups, err := pgc.productGroupService.GetProductGroupsByParentId(parentId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, productGroups) +} + +func (pgc *ProductGroupController) DeleteProductFromProductGroupId(c *gin.Context) { + productId, err := strconv.Atoi(c.Param("productId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product ID"}) + return + } + err = pgc.productGroupService.DeleteProductFromProductGroupId(productId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "Product deleted from product group successfully"}) +} + +func (pgc *ProductGroupController) GetPropertiesFromProductGroupId(c *gin.Context) { + productGroupId, err := strconv.Atoi(c.Param("productGroupId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product group ID"}) + return + } + properties, err := pgc.productGroupService.GetPropertiesFromProductGroupId(productGroupId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, properties) +} + +func (pgc *ProductGroupController) DeletePropertyFromProductGroupId(c *gin.Context) { + propertyId, err := strconv.Atoi(c.Param("propertyId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid property ID"}) + return + } + productGroupId, err := strconv.Atoi(c.Param("productGroupId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product group ID"}) + return + } + err = pgc.productGroupService.DeletePropertyFromProductGroup(productGroupId, propertyId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "Property deleted from product group successfully"}) +} + +func (pgc *ProductGroupController) CreatePropertyToProductGroupId(c *gin.Context) { + var property models.Property + if err := c.ShouldBindJSON(&property); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + productGroupId, err := strconv.Atoi(c.Param("productGroupId")) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product group ID"}) + return + } + + property2, err := pgc.productGroupService.CreatePropertyToProductGroupId(productGroupId, &property) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, property2) +} diff --git a/buildtime/server/models/value.go b/buildtime/server/models/value.go index ed14a9306..356161c7c 100644 --- a/buildtime/server/models/value.go +++ b/buildtime/server/models/value.go @@ -19,6 +19,8 @@ type Property struct { Label string `json:"label"` Description string `json:"description"` PropertyTypeID int `json:"propertyTypeId"` + ProductID int `json:"productId"` + ProductGroupID int `json:"productGroupId"` } type Value struct { diff --git a/buildtime/server/repositories/productGroupRepository.go b/buildtime/server/repositories/productGroupRepository.go new file mode 100644 index 000000000..1598f056b --- /dev/null +++ b/buildtime/server/repositories/productGroupRepository.go @@ -0,0 +1,152 @@ +package repositories + +import ( + "database/sql" + "simplycpq/models" +) + +type ProductGroupRepository struct { + db *sql.DB + valueRepository *ValueRepository +} + +func NewProductGroupRepository(db *sql.DB, valueRepository *ValueRepository) *ProductGroupRepository { + return &ProductGroupRepository{ + db: db, + valueRepository: valueRepository, + } +} + +func (r *ProductGroupRepository) CreateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) { + // Insert the product group into the database + query := "INSERT INTO product_groups (label, description, parentgroupid) VALUES($1,$2,$3) RETURNING id" + err := r.db.QueryRow(query, productGroup.Label, productGroup.Description, productGroup.ParentGroupID).Scan(&productGroup.ID) + if err != nil { + return nil, err + } + + // get all properties from parent group and copy them to the new group + if productGroup.ParentGroupID != 0 { + properties, err := r.GetPropertiesFromProductGroupId(productGroup.ParentGroupID) + if err != nil { + return nil, err + } + for _, prop := range properties { + _, err := r.valueRepository.createPropertyFromProperty(productGroup.ID, 0, prop) + if err != nil { + return nil, err + } + } + } + return productGroup, nil +} + +func (r *ProductGroupRepository) UpdateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) { + query := "UPDATE product_groups SET label=$1, description=$2, parentgroupid=$3 WHERE id=$4" + _, err := r.db.Exec(query, productGroup.Label, productGroup.Description, productGroup.ParentGroupID, productGroup.ID) + if err != nil { + return nil, err + } + return productGroup, nil +} + +func (r *ProductGroupRepository) DeleteProductGroup(id int) error { + query := "DELETE FROM product_groups WHERE id=$1" + _, err := r.db.Exec(query, id) + if err != nil { + return err + } + return nil +} + +func (r *ProductGroupRepository) GetProductGroup(id int) (*models.ProductGroup, error) { + query := "SELECT id, label, description, parentgroupid FROM product_groups WHERE id=$1" + row := r.db.QueryRow(query, id) + productGroup := &models.ProductGroup{} + err := row.Scan(&productGroup.ID, &productGroup.Label, &productGroup.Description, &productGroup.ParentGroupID) + if err != nil { + return nil, err + } + return productGroup, nil +} + +func (r *ProductGroupRepository) GetProductGroupsByParentId(parentId int) ([]*models.ProductGroup, error) { + query := "SELECT id, label, description, parentgroupid FROM product_groups WHERE parentgroupid=$1" + rows, err := r.db.Query(query, parentId) + if err != nil { + return nil, err + } + defer rows.Close() + + var productGroups []*models.ProductGroup + for rows.Next() { + var productGroup models.ProductGroup + err := rows.Scan(&productGroup.ID, &productGroup.Label, &productGroup.Description, &productGroup.ParentGroupID) + if err != nil { + return nil, err + } + productGroups = append(productGroups, &productGroup) + } + if err = rows.Err(); err != nil { + return nil, err + } + return productGroups, nil +} + +func (r *ProductGroupRepository) DeleteProductFromProductGroupId(productGroupId int) error { + query := "DELETE FROM products WHERE productgroupid=$1" + _, err := r.db.Exec(query, productGroupId) + if err != nil { + return err + } + return nil +} + +func (r *ProductGroupRepository) GetPropertiesFromProductGroupId(productGroupId int) ([]*models.Property, error) { + query := "SELECT id, label, description, propertytypeid, productid, productgroupid FROM properties WHERE productgroupid=$1" + rows, err := r.db.Query(query, productGroupId) + if err != nil { + return nil, err + } + defer rows.Close() + + var properties []*models.Property + for rows.Next() { + var property models.Property + err := rows.Scan(&property.ID, &property.Label, &property.Description, &property.PropertyTypeID, &property.ProductID, &property.ProductGroupID) + if err != nil { + return nil, err + } + properties = append(properties, &property) + } + if err = rows.Err(); err != nil { + return nil, err + } + return properties, nil +} + +func (r *ProductGroupRepository) DeletePropertyFromProductGroup(productGroupId int, propertyId int) error { + query := "DELETE FROM properties WHERE productgroupid=$1 AND id=$2" + _, err := r.db.Exec(query, productGroupId, propertyId) + if err != nil { + return err + } + return nil +} + +func (r *ProductGroupRepository) CreatePropertyFromProductGroup(productGroupId int, property *models.Property) (*models.Property, error) { + query := "INSERT INTO properties (label, description, propertytypeid, productid, productgroupid) VALUES($1,$2,$3,$4,$5) RETURNING id" + err := r.db.QueryRow(query, property.Label, property.Description, property.PropertyTypeID, property.ProductID, productGroupId).Scan(&property.ID) + if err != nil { + return nil, err + } + + // copy property values from parent group to new property + if productGroupId != 0 { + err := r.valueRepository.copyValuesFromPropertyTypeToProperty(property.ID, property.PropertyTypeID) + if err != nil { + return nil, err + } + } + return property, nil +} \ No newline at end of file diff --git a/buildtime/server/repositories/productRepository.go b/buildtime/server/repositories/productRepository.go new file mode 100644 index 000000000..c6704efa2 --- /dev/null +++ b/buildtime/server/repositories/productRepository.go @@ -0,0 +1,126 @@ +package repositories + +import ( + "database/sql" + "simplycpq/models" +) + +type ProductRepository struct { + dbHandler *sql.DB + productGroupRepository *ProductGroupRepository + valueRepository *ValueRepository +} + +func NewProductRepository(dbHandler *sql.DB, productGroupRepository *ProductGroupRepository, valueRepository *ValueRepository) *ProductRepository { + return &ProductRepository{ + dbHandler: dbHandler, + productGroupRepository: productGroupRepository, + valueRepository: valueRepository, + } +} + +func (pr *ProductRepository) CreateProduct(product *models.Product) (*models.Product, error) { + // Implement the logic to insert a new product into the database + query := "INSERT INTO products (label, externalId, description, productGroupId) VALUES ($1, $2, $3, $4) RETURNING id" + err := pr.dbHandler.QueryRow(query, product.Label, product.ExternalID, product.Description, product.ProductGroupID).Scan(&product.ID) + if err != nil { + return nil, err + } + + // copy Properties from ProductGroup to Product + properties, err := pr.productGroupRepository.GetPropertiesFromProductGroupId(product.ProductGroupID) + if err != nil { + return nil, err + } + + for _, property := range properties { + _, err := pr.valueRepository.createPropertyFromProperty(0, product.ID, property) + if err != nil { + return nil, err + } + } + + return product, nil +} + +func (pr *ProductRepository) GetProductById(id int) (*models.Product, error) { + // Implement the logic to retrieve a product by its ID from the database + query := "SELECT id, label, externalId, description, productGroupId FROM products WHERE id = $1" + row := pr.dbHandler.QueryRow(query, id) + product := &models.Product{} + err := row.Scan(&product.ID, &product.Label, &product.ExternalID, &product.Description, &product.ProductGroupID) + if err != nil { + return nil, err + } + return product, nil +} + +func (pr *ProductRepository) UpdateProduct(product *models.Product) error { + // Implement the logic to update an existing product in the database + query := "UPDATE products SET label = $1, externalId = $2, description = $3, productGroupId = $4 WHERE id = $5" + _, err := pr.dbHandler.Exec(query, product.Label, product.ExternalID, product.Description, product.ProductGroupID, product.ID) + return err +} + +func (pr *ProductRepository) DeleteProduct(id int) error { + // Implement the logic to delete a product from the database + query := "DELETE FROM products WHERE id = $1" + _, err := pr.dbHandler.Exec(query, id) + return err +} + +func (pr *ProductRepository) GetProductsByGroupId(groupId int) ([]*models.Product, error) { + // Implement the logic to retrieve all products by their group ID from the database + query := "SELECT id, label, externalId, description, productGroupId FROM products WHERE productGroupId = $1" + rows, err := pr.dbHandler.Query(query, groupId) + if err != nil { + return nil, err + } + defer rows.Close() + + products := []*models.Product{} + for rows.Next() { + product := &models.Product{} + err := rows.Scan(&product.ID, &product.Label, &product.ExternalID, &product.Description, &product.ProductGroupID) + if err != nil { + return nil, err + } + products = append(products, product) + } + return products, nil +} + +func (pr *ProductRepository) AddPropertyToProduct(productId int, propertyId int) error { + // Implement the logic to add a property to a product in the database + query := "INSERT INTO product_properties (productId, propertyId) VALUES ($1, $2)" + _, err := pr.dbHandler.Exec(query, productId, propertyId) + return err +} + +func (pr *ProductRepository) DeletePropertyFromProduct(productId int, propertyId int) error { + // Implement the logic to delete a property from a product in the database + query := "DELETE FROM product_properties WHERE productId = $1 AND propertyId = $2" + _, err := pr.dbHandler.Exec(query, productId, propertyId) + return err +} + +func (pr *ProductRepository) GetPropertiesFromProduct(productId int) ([]*models.Property, error) { + // Implement the logic to retrieve all properties from a product in the database + query := "SELECT id, label, description, propertyTypeId, productId, productGroupId FROM properties WHERE productId = $1" + rows, err := pr.dbHandler.Query(query, productId) + if err != nil { + return nil, err + } + defer rows.Close() + + properties := []*models.Property{} + for rows.Next() { + property := &models.Property{} + err := rows.Scan(&property.ID, &property.Label, &property.Description, &property.PropertyTypeID, &property.ProductID, &property.ProductGroupID) + if err != nil { + return nil, err + } + properties = append(properties, property) + } + return properties, nil +} diff --git a/buildtime/server/repositories/valueRepository.go b/buildtime/server/repositories/valueRepository.go index e445700b4..b71729474 100644 --- a/buildtime/server/repositories/valueRepository.go +++ b/buildtime/server/repositories/valueRepository.go @@ -267,6 +267,48 @@ func (vr *ValueRepository) GetValue(id int) (*models.Value, error) { return &value, nil } +func (vr *ValueRepository) createPropertyFromPropertyType(productGroupId int, productId int, propertyType *models.PropertyType) (*models.Property, error) { + query := `INSERT INTO properties (label, description, propertytypeid, productid, productgroupid) VALUES ($1, $2, $3, $4, $5) RETURNING id` + var property models.Property + err := vr.db.QueryRow(query, propertyType.Label, propertyType.Description, propertyType.ID, productId, productGroupId).Scan(&property.ID) + if err != nil { + return nil, err + } + property.Label = propertyType.Label + property.Description = propertyType.Description + property.PropertyTypeID = propertyType.ID + property.ProductID = productId + property.ProductGroupID = productGroupId + + // Copy values from property type to property + err = vr.copyValuesFromPropertyTypeToProperty(propertyType.ID, property.ID) + if err != nil { + return nil, err + } + return &property, nil +} + +func (vr *ValueRepository) createPropertyFromProperty(productGroupId int, productId int, property *models.Property) (*models.Property, error) { + query := `INSERT INTO properties (label, description, propertytypeid, productid, productgroupid) VALUES ($1, $2, $3, $4, $5) RETURNING id` + var newProperty models.Property + err := vr.db.QueryRow(query, property.Label, property.Description, property.PropertyTypeID, productId, productGroupId).Scan(&newProperty.ID) + if err != nil { + return nil, err + } + newProperty.Label = property.Label + newProperty.Description = property.Description + newProperty.PropertyTypeID = property.PropertyTypeID + newProperty.ProductID = productId + newProperty.ProductGroupID = productGroupId + + // Copy values from property type to property + err = vr.copyValuesFromPropertyToProperty(property.ID, newProperty.ID) + if err != nil { + return nil, err + } + return &newProperty, nil +} + func (vr *ValueRepository) copyValuesFromPropertyTypeToProperty(propertyTypeId int, propertyId int) error { // Implement the logic to copy values from a property type to a property query := `INSERT INTO values (propertyId, label, description) SELECT $1, label, description FROM values WHERE propertytypeid=$2` diff --git a/buildtime/server/server/httpServer.go b/buildtime/server/server/httpServer.go index f1810c896..1e0b882f2 100644 --- a/buildtime/server/server/httpServer.go +++ b/buildtime/server/server/httpServer.go @@ -15,20 +15,30 @@ import ( ) type HttpServer struct { - config *viper.Viper - router *gin.Engine - dbHandler *sql.DB - valueController *controller.ValueController + config *viper.Viper + router *gin.Engine + dbHandler *sql.DB + valueController *controller.ValueController + productGroupController *controller.ProductGroupController + productController *controller.ProductController } func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer { // repository initialisation: valueRepository := repositories.NewValueRepository(dbHandler) + productGroupRepository := repositories.NewProductGroupRepository(dbHandler, valueRepository) + productRepository := repositories.NewProductRepository(dbHandler, productGroupRepository, valueRepository) + // service initialisation: valueService := services.NewValueService(valueRepository) + productGroupService := services.NewProductGroupService(productGroupRepository) + productService := services.NewProductService(productRepository) + // controller initialisation: valueController := controller.NewValueController(valueService) + productGroupController := controller.NewProductGroupController(productGroupService, valueService) + productController := controller.NewProductController(productService, productGroupService, valueService) // Service API router := gin.Default() @@ -55,13 +65,34 @@ func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer { router.GET("/getValue/:id", valueController.GetValue) // get Value by id // Product centric routing + // ProductGroup + router.POST("/createProductGroup", productGroupController.CreateProductGroup) // create ProductGroup + router.PUT("/updateProductGroup", productGroupController.UpdateProductGroup) // update ProductGroup + router.DELETE("/deleteProductGroup/:id", productGroupController.DeleteProductGroup) // delete ProductGroup + router.GET("/getProductGroup/:id", productGroupController.GetProductGroup) // get ProductGroup by id + router.GET("/getProductGroupsByParentId/:parentId", productGroupController.GetProductGroupsByParentId) // get all ProductGroups by parent ID + router.DELETE("/deleteProductFromProductGroupId/:productId", productGroupController.DeleteProductFromProductGroupId) // delete Product from ProductGroup by ID + router.POST("/getPropertiesFromProductGroupId/:productGroupId", productGroupController.GetPropertiesFromProductGroupId) // get Properties from ProductGroup by ID + router.DELETE("/deletePropertyFromProductGroupId/:propertyId/:productGroupId", productGroupController.DeletePropertyFromProductGroupId) // delete Property from ProductGroup by ID + router.POST("/createPropertyToProductGroupId/:propertyTypeId/:productGroupId", productGroupController.CreatePropertyToProductGroupId) // add Property to ProductGroup by ID + + // Product + router.POST("/createProduct", productController.CreateProduct) // create Product + router.PUT("/updateProduct", productController.UpdateProduct) // update Product + router.DELETE("/deleteProduct/:id", productController.DeleteProduct) // delete Product + router.GET("/getProduct/:id", productController.GetProduct) // get Product by id + router.GET("/getProductsByGroupId/:groupId", productController.GetProductsByGroupId) // get all Products by group 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 // server return HttpServer{ - config: config, - router: router, - dbHandler: dbHandler, - valueController: valueController, + config: config, + router: router, + dbHandler: dbHandler, + valueController: valueController, + productGroupController: productGroupController, + productController: productController, } } diff --git a/buildtime/server/services/productGroupService.go b/buildtime/server/services/productGroupService.go new file mode 100644 index 000000000..cbd7c0d27 --- /dev/null +++ b/buildtime/server/services/productGroupService.go @@ -0,0 +1,56 @@ +package services + +import ( + "simplycpq/models" + "simplycpq/repositories" +) + +type ProductGroupService struct { + productGroupRepository *repositories.ProductGroupRepository +} + +func NewProductGroupService(productGroupRepository *repositories.ProductGroupRepository) *ProductGroupService { + return &ProductGroupService{ + productGroupRepository: productGroupRepository, + } +} + +func (s *ProductGroupService) CreateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) { + return s.productGroupRepository.CreateProductGroup(productGroup) +} + +func (s *ProductGroupService) UpdateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) { + return s.productGroupRepository.UpdateProductGroup(productGroup) +} + +func (s *ProductGroupService) DeleteProductGroup(id int) error { + return s.productGroupRepository.DeleteProductGroup(id) +} + +func (s *ProductGroupService) GetProductGroup(id int) (*models.ProductGroup, error) { + return s.productGroupRepository.GetProductGroup(id) +} + +func (s *ProductGroupService) GetPropertiesFromProductGroupId(id int) ([]*models.Property, error) { + return s.productGroupRepository.GetPropertiesFromProductGroupId(id) +} + +func (s *ProductGroupService) GetProductGroupsByParentId(parentId int) ([]*models.ProductGroup, error) { + return s.productGroupRepository.GetProductGroupsByParentId(parentId) +} + +func (s *ProductGroupService) DeleteProductFromProductGroupId(productGroupId int) error { + return s.productGroupRepository.DeleteProductFromProductGroupId(productGroupId) +} + +func (s *ProductGroupService) GetPropertiesFromProductGroup(productGroupId int) ([]*models.Property, error) { + return s.productGroupRepository.GetPropertiesFromProductGroupId(productGroupId) +} + +func (s *ProductGroupService) DeletePropertyFromProductGroup(productGroupId int, propertyId int) error { + return s.productGroupRepository.DeletePropertyFromProductGroup(productGroupId, propertyId) +} + +func (s *ProductGroupService) CreatePropertyToProductGroupId(productGroupId int, property *models.Property) (*models.Property, error) { + return s.productGroupRepository.CreatePropertyFromProductGroup(productGroupId, property) +} diff --git a/buildtime/server/services/productService.go b/buildtime/server/services/productService.go new file mode 100644 index 000000000..7ca6e539f --- /dev/null +++ b/buildtime/server/services/productService.go @@ -0,0 +1,51 @@ +package services + +import ( + "simplycpq/models" + "simplycpq/repositories" +) + +type ProductService struct { + productRepository *repositories.ProductRepository +} + +func NewProductService(productRepository *repositories.ProductRepository) *ProductService { + return &ProductService{ + productRepository: productRepository, + } +} + +func (s *ProductService) CreateProduct(product *models.Product) (*models.Product, error) { + return s.productRepository.CreateProduct(product) +} +func (s *ProductService) UpdateProduct(product *models.Product) error { + return s.productRepository.UpdateProduct(product) +} + +func (s *ProductService) DeleteProduct(id int) error { + return s.productRepository.DeleteProduct(id) +} + +func (s *ProductService) GetProduct(id int) (*models.Product, error) { + return s.productRepository.GetProductById(id) +} + +func (s *ProductService) GetProductById(id int) (*models.Product, error) { + return s.productRepository.GetProductById(id) +} + +func (s *ProductService) GetProductsByGroupId(groupId int) ([]*models.Product, error) { + return s.productRepository.GetProductsByGroupId(groupId) +} + +func (s *ProductService) AddPropertyToProduct(productId int, propertyId int) error { + return s.productRepository.AddPropertyToProduct(productId, propertyId) +} + +func (s *ProductService) DeletePropertyFromProduct(productId int, propertyId int) error { + return s.productRepository.DeletePropertyFromProduct(productId, propertyId) +} + +func (s *ProductService) GetPropertiesFromProduct(productId int) ([]*models.Property, error) { + return s.productRepository.GetPropertiesFromProduct(productId) +}