package handler import ( "apskel-pos-be/internal/appcontext" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/contract" "apskel-pos-be/internal/logger" "apskel-pos-be/internal/models" "apskel-pos-be/internal/service" "apskel-pos-be/internal/util" "net/http" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type ProductRecipeHandler struct { productRecipeService service.ProductRecipeService } func NewProductRecipeHandler(productRecipeService service.ProductRecipeService) *ProductRecipeHandler { return &ProductRecipeHandler{ productRecipeService: productRecipeService, } } func (h *ProductRecipeHandler) Create(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) var request models.CreateProductRecipeRequest if err := c.ShouldBindJSON(&request); err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Create -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Create") return } recipeResponse, err := h.productRecipeService.Create(ctx, contextInfo.OrganizationID, &request) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Create -> Failed to create product recipe") validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Create") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipeResponse), "ProductRecipeHandler::Create") } func (h *ProductRecipeHandler) GetByID(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) idStr := c.Param("id") id, err := uuid.Parse(idStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByID -> Invalid recipe ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid recipe ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByID") return } recipeResponse, err := h.productRecipeService.GetByID(ctx, id, contextInfo.OrganizationID) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByID -> Failed to get product recipe") validationResponseError := contract.NewResponseError(constants.NotFoundErrorCode, constants.RequestEntity, "Product recipe not found") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByID") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipeResponse), "ProductRecipeHandler::GetByID") } func (h *ProductRecipeHandler) GetByProductID(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) productIDStr := c.Param("product_id") productID, err := uuid.Parse(productIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByProductID -> Invalid product ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByProductID") return } // Check if variant_id is provided variantIDStr := c.Query("variant_id") var variantID *uuid.UUID if variantIDStr != "" { parsed, err := uuid.Parse(variantIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByProductID -> Invalid variant ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid variant ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByProductID") return } variantID = &parsed } var recipes []*models.ProductRecipeResponse if variantIDStr != "" { // Get by product and variant ID recipes, err = h.productRecipeService.GetByProductAndVariantID(ctx, productID, variantID, contextInfo.OrganizationID) } else { // Get by product ID only recipes, err = h.productRecipeService.GetByProductID(ctx, productID, contextInfo.OrganizationID) } if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByProductID -> Failed to get product recipes") validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByProductID") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipes), "ProductRecipeHandler::GetByProductID") } func (h *ProductRecipeHandler) GetByIngredientID(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) ingredientIDStr := c.Param("ingredient_id") ingredientID, err := uuid.Parse(ingredientIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByIngredientID -> Invalid ingredient ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByIngredientID") return } recipes, err := h.productRecipeService.GetByIngredientID(ctx, ingredientID, contextInfo.OrganizationID) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::GetByIngredientID -> Failed to get product recipes") validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::GetByIngredientID") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipes), "ProductRecipeHandler::GetByIngredientID") } func (h *ProductRecipeHandler) Update(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) idStr := c.Param("id") id, err := uuid.Parse(idStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Update -> Invalid recipe ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid recipe ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Update") return } var request models.UpdateProductRecipeRequest if err := c.ShouldBindJSON(&request); err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Update -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Update") return } recipeResponse, err := h.productRecipeService.Update(ctx, id, contextInfo.OrganizationID, &request) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Update -> Failed to update product recipe") validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Update") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(recipeResponse), "ProductRecipeHandler::Update") } func (h *ProductRecipeHandler) Delete(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) idStr := c.Param("id") id, err := uuid.Parse(idStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Delete -> Invalid recipe ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid recipe ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Delete") return } err = h.productRecipeService.Delete(ctx, id, contextInfo.OrganizationID) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::Delete -> Failed to delete product recipe") validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::Delete") return } response := map[string]interface{}{ "message": "Product recipe deleted successfully", } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(response), "ProductRecipeHandler::Delete") } func (h *ProductRecipeHandler) BulkCreate(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) var request struct { Recipes []models.CreateProductRecipeRequest `json:"recipes" validate:"required,min=1"` } if err := c.ShouldBindJSON(&request); err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::BulkCreate -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::BulkCreate") return } recipes, err := h.productRecipeService.BulkCreate(ctx, contextInfo.OrganizationID, request.Recipes) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductRecipeHandler::BulkCreate -> Failed to bulk create product recipes") validationResponseError := contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductRecipeHandler::BulkCreate") return } c.JSON(http.StatusCreated, contract.BuildSuccessResponse(recipes)) }