package handler import ( "strconv" "apskel-pos-be/internal/appcontext" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/contract" "apskel-pos-be/internal/logger" "apskel-pos-be/internal/service" "apskel-pos-be/internal/util" "apskel-pos-be/internal/validator" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type ProductHandler struct { productService service.ProductService productValidator validator.ProductValidator } func NewProductHandler( productService service.ProductService, productValidator validator.ProductValidator, ) *ProductHandler { return &ProductHandler{ productService: productService, productValidator: productValidator, } } func (h *ProductHandler) CreateProduct(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) var req contract.CreateProductRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("ProductHandler::CreateProduct -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::CreateProduct") return } validationError, validationErrorCode := h.productValidator.ValidateCreateProductRequest(&req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::CreateProduct") return } productResponse := h.productService.CreateProduct(ctx, contextInfo, &req) if productResponse.HasErrors() { errorResp := productResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::CreateProduct -> Failed to create product from service") } util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::CreateProduct") } func (h *ProductHandler) UpdateProduct(c *gin.Context) { ctx := c.Request.Context() productIDStr := c.Param("id") productID, err := uuid.Parse(productIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductHandler::UpdateProduct -> Invalid product ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::UpdateProduct") return } var req contract.UpdateProductRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(ctx).WithError(err).Error("ProductHandler::UpdateProduct -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::UpdateProduct") return } validationError, validationErrorCode := h.productValidator.ValidateUpdateProductRequest(&req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::UpdateProduct") return } productResponse := h.productService.UpdateProduct(ctx, productID, &req) if productResponse.HasErrors() { errorResp := productResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::UpdateProduct -> Failed to update product from service") } util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::UpdateProduct") } func (h *ProductHandler) DeleteProduct(c *gin.Context) { ctx := c.Request.Context() productIDStr := c.Param("id") productID, err := uuid.Parse(productIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductHandler::DeleteProduct -> Invalid product ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::DeleteProduct") return } productResponse := h.productService.DeleteProduct(ctx, productID) if productResponse.HasErrors() { errorResp := productResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::DeleteProduct -> Failed to delete product from service") } util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::DeleteProduct") } func (h *ProductHandler) GetProduct(c *gin.Context) { ctx := c.Request.Context() productIDStr := c.Param("id") productID, err := uuid.Parse(productIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("ProductHandler::GetProduct -> Invalid product ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::GetProduct") return } productResponse := h.productService.GetProductByID(ctx, productID) if productResponse.HasErrors() { errorResp := productResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::GetProduct -> Failed to get product from service") } util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::GetProduct") } func (h *ProductHandler) ListProducts(c *gin.Context) { ctx := c.Request.Context() req := &contract.ListProductsRequest{ Page: 1, Limit: 10, } // Parse query parameters if pageStr := c.Query("page"); pageStr != "" { if page, err := strconv.Atoi(pageStr); err == nil { req.Page = page } } if limitStr := c.Query("limit"); limitStr != "" { if limit, err := strconv.Atoi(limitStr); err == nil { req.Limit = limit } } if search := c.Query("search"); search != "" { req.Search = search } if businessType := c.Query("business_type"); businessType != "" { req.BusinessType = businessType } if organizationIDStr := c.Query("organization_id"); organizationIDStr != "" { if organizationID, err := uuid.Parse(organizationIDStr); err == nil { req.OrganizationID = &organizationID } } if categoryIDStr := c.Query("category_id"); categoryIDStr != "" { if categoryID, err := uuid.Parse(categoryIDStr); err == nil { req.CategoryID = &categoryID } } if isActiveStr := c.Query("is_active"); isActiveStr != "" { if isActive, err := strconv.ParseBool(isActiveStr); err == nil { req.IsActive = &isActive } } if minPriceStr := c.Query("min_price"); minPriceStr != "" { if minPrice, err := strconv.ParseFloat(minPriceStr, 64); err == nil { req.MinPrice = &minPrice } } if maxPriceStr := c.Query("max_price"); maxPriceStr != "" { if maxPrice, err := strconv.ParseFloat(maxPriceStr, 64); err == nil { req.MaxPrice = &maxPrice } } validationError, validationErrorCode := h.productValidator.ValidateListProductsRequest(req) if validationError != nil { logger.FromContext(ctx).WithError(validationError).Error("ProductHandler::ListProducts -> request validation failed") validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::ListProducts") return } productsResponse := h.productService.ListProducts(ctx, req) if productsResponse.HasErrors() { errorResp := productsResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::ListProducts -> Failed to list products from service") } util.HandleResponse(c.Writer, c.Request, productsResponse, "ProductHandler::ListProducts") }