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/util" "strconv" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type IngredientHandler struct { ingredientService IngredientService } func NewIngredientHandler(ingredientService IngredientService) *IngredientHandler { return &IngredientHandler{ingredientService: ingredientService} } func (h *IngredientHandler) Create(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) var request models.CreateIngredientRequest if err := c.ShouldBindJSON(&request); err != nil { logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Create -> request binding failed") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::Create") return } request.OrganizationID = contextInfo.OrganizationID resp, err := h.ingredientService.CreateIngredient(ctx, &request) if err != nil { logger.FromContext(ctx).WithError(err).Error("IngredientHandler::Create -> failed") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::Create") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::Create") } func (h *IngredientHandler) GetByID(c *gin.Context) { ctx := c.Request.Context() id, err := uuid.Parse(c.Param("id")) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID"), }), "IngredientHandler::GetByID") return } resp, err := h.ingredientService.GetIngredientByID(ctx, id) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.NotFoundErrorCode, constants.RequestEntity, "Ingredient not found"), }), "IngredientHandler::GetByID") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::GetByID") } func (h *IngredientHandler) GetAll(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) pageStr := c.DefaultQuery("page", "1") limitStr := c.DefaultQuery("limit", "10") search := c.Query("search") outletIDStr := c.Query("outlet_id") page, err := strconv.Atoi(pageStr) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid page parameter"), }), "IngredientHandler::GetAll") return } limit, err := strconv.Atoi(limitStr) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid limit parameter"), }), "IngredientHandler::GetAll") return } var outletID *uuid.UUID if outletIDStr != "" { parsed, err := uuid.Parse(outletIDStr) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID"), }), "IngredientHandler::GetAll") return } outletID = &parsed } resp, err := h.ingredientService.ListIngredients(ctx, contextInfo.OrganizationID, outletID, page, limit, search) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, "Failed to get ingredients"), }), "IngredientHandler::GetAll") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::GetAll") } func (h *IngredientHandler) Update(c *gin.Context) { ctx := c.Request.Context() id, err := uuid.Parse(c.Param("id")) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID"), }), "IngredientHandler::Update") return } var request models.UpdateIngredientRequest if err := c.ShouldBindJSON(&request); err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body"), }), "IngredientHandler::Update") return } resp, err := h.ingredientService.UpdateIngredient(ctx, id, &request) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::Update") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::Update") } func (h *IngredientHandler) Delete(c *gin.Context) { ctx := c.Request.Context() id, err := uuid.Parse(c.Param("id")) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid ingredient ID"), }), "IngredientHandler::Delete") return } if err := h.ingredientService.DeleteIngredient(ctx, id); err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::Delete") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(map[string]string{ "message": "Ingredient deleted successfully", }), "IngredientHandler::Delete") } // AddCompositions adds multiple composition items to a semi-finished ingredient. func (h *IngredientHandler) AddCompositions(c *gin.Context) { ctx := c.Request.Context() id, err := uuid.Parse(c.Param("id")) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "invalid ingredient id"), }), "IngredientHandler::AddCompositions") return } var req models.AddIngredientCompositionsRequest if err := c.ShouldBindJSON(&req); err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::AddCompositions") return } resp, err := h.ingredientService.AddCompositions(ctx, id, &req) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::AddCompositions") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::AddCompositions") } // UpdateComposition updates quantity/outlet of a single composition entry. func (h *IngredientHandler) UpdateComposition(c *gin.Context) { ctx := c.Request.Context() id, err := uuid.Parse(c.Param("composition_id")) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "invalid composition id"), }), "IngredientHandler::UpdateComposition") return } var req models.UpdateIngredientCompositionRequest if err := c.ShouldBindJSON(&req); err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::UpdateComposition") return } resp, err := h.ingredientService.UpdateComposition(ctx, id, &req) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::UpdateComposition") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::UpdateComposition") } // DeleteComposition removes a single composition entry. func (h *IngredientHandler) DeleteComposition(c *gin.Context) { ctx := c.Request.Context() id, err := uuid.Parse(c.Param("composition_id")) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "invalid composition id"), }), "IngredientHandler::DeleteComposition") return } resp, err := h.ingredientService.DeleteComposition(ctx, id) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.InternalServerErrorCode, constants.RequestEntity, err.Error()), }), "IngredientHandler::DeleteComposition") return } util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(resp), "IngredientHandler::DeleteComposition") }