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 InventoryHandler struct { inventoryService service.InventoryService inventoryValidator validator.InventoryValidator } func NewInventoryHandler( inventoryService service.InventoryService, inventoryValidator validator.InventoryValidator, ) *InventoryHandler { return &InventoryHandler{ inventoryService: inventoryService, inventoryValidator: inventoryValidator, } } func (h *InventoryHandler) CreateInventory(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) var req contract.CreateInventoryRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(c.Request.Context()).WithError(err).Error("InventoryHandler::CreateInventory -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::CreateInventory") return } validationError, validationErrorCode := h.inventoryValidator.ValidateCreateInventoryRequest(&req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::CreateInventory") return } inventoryResponse := h.inventoryService.CreateInventory(ctx, contextInfo, &req) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::CreateInventory -> Failed to create inventory from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::CreateInventory") } func (h *InventoryHandler) UpdateInventory(c *gin.Context) { ctx := c.Request.Context() inventoryIDStr := c.Param("id") inventoryID, err := uuid.Parse(inventoryIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("InventoryHandler::UpdateInventory -> Invalid inventory ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid inventory ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::UpdateInventory") return } var req contract.UpdateInventoryRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(ctx).WithError(err).Error("InventoryHandler::UpdateInventory -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::UpdateInventory") return } validationError, validationErrorCode := h.inventoryValidator.ValidateUpdateInventoryRequest(&req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::UpdateInventory") return } inventoryResponse := h.inventoryService.UpdateInventory(ctx, inventoryID, &req) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::UpdateInventory -> Failed to update inventory from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::UpdateInventory") } func (h *InventoryHandler) DeleteInventory(c *gin.Context) { ctx := c.Request.Context() inventoryIDStr := c.Param("id") inventoryID, err := uuid.Parse(inventoryIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("InventoryHandler::DeleteInventory -> Invalid inventory ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid inventory ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::DeleteInventory") return } inventoryResponse := h.inventoryService.DeleteInventory(ctx, inventoryID) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::DeleteInventory -> Failed to delete inventory from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::DeleteInventory") } func (h *InventoryHandler) GetInventory(c *gin.Context) { ctx := c.Request.Context() inventoryIDStr := c.Param("id") inventoryID, err := uuid.Parse(inventoryIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetInventory -> Invalid inventory ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid inventory ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetInventory") return } inventoryResponse := h.inventoryService.GetInventoryByID(ctx, inventoryID) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::GetInventory -> Failed to get inventory from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::GetInventory") } func (h *InventoryHandler) ListInventory(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) req := &contract.ListInventoryRequest{ Page: 1, Limit: 10, OutletID: &contextInfo.OutletID, } 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 outletIDStr := c.Query("outlet_id"); outletIDStr != "" { if outletID, err := uuid.Parse(outletIDStr); err == nil { req.OutletID = &outletID } } if productIDStr := c.Query("product_id"); productIDStr != "" { if productID, err := uuid.Parse(productIDStr); err == nil { req.ProductID = &productID } } if categoryIDStr := c.Query("category_id"); categoryIDStr != "" { if categoryID, err := uuid.Parse(categoryIDStr); err == nil { req.CategoryID = &categoryID } } if lowStockStr := c.Query("low_stock_only"); lowStockStr != "" { if lowStock, err := strconv.ParseBool(lowStockStr); err == nil { req.LowStockOnly = &lowStock } } if zeroStockStr := c.Query("zero_stock_only"); zeroStockStr != "" { if zeroStock, err := strconv.ParseBool(zeroStockStr); err == nil { req.ZeroStockOnly = &zeroStock } } validationError, validationErrorCode := h.inventoryValidator.ValidateListInventoryRequest(req) if validationError != nil { logger.FromContext(ctx).WithError(validationError).Error("InventoryHandler::ListInventory -> request validation failed") validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::ListInventory") return } inventoryResponse := h.inventoryService.ListInventory(ctx, req) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::ListInventory -> Failed to list inventory from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::ListInventory") } func (h *InventoryHandler) AdjustInventory(c *gin.Context) { ctx := c.Request.Context() var req contract.AdjustInventoryRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(ctx).WithError(err).Error("InventoryHandler::AdjustInventory -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::AdjustInventory") return } validationError, validationErrorCode := h.inventoryValidator.ValidateAdjustInventoryRequest(&req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::AdjustInventory") return } inventoryResponse := h.inventoryService.AdjustInventory(ctx, &req) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::AdjustInventory -> Failed to adjust inventory from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::AdjustInventory") } func (h *InventoryHandler) GetLowStockItems(c *gin.Context) { ctx := c.Request.Context() outletIDStr := c.Param("outlet_id") outletID, err := uuid.Parse(outletIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetLowStockItems -> Invalid outlet ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetLowStockItems") return } inventoryResponse := h.inventoryService.GetLowStockItems(ctx, outletID) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::GetLowStockItems -> Failed to get low stock items from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::GetLowStockItems") } func (h *InventoryHandler) GetZeroStockItems(c *gin.Context) { ctx := c.Request.Context() outletIDStr := c.Param("outlet_id") outletID, err := uuid.Parse(outletIDStr) if err != nil { logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetZeroStockItems -> Invalid outlet ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetZeroStockItems") return } inventoryResponse := h.inventoryService.GetZeroStockItems(ctx, outletID) if inventoryResponse.HasErrors() { errorResp := inventoryResponse.GetErrors()[0] logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::GetZeroStockItems -> Failed to get zero stock items from service") } util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::GetZeroStockItems") }