package handler import ( "apskel-pos-be/internal/contract" "apskel-pos-be/internal/service" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type TableHandler struct { tableService *service.TableService } func NewTableHandler(tableService *service.TableService) *TableHandler { return &TableHandler{ tableService: tableService, } } // CreateTable godoc // @Summary Create a new table // @Description Create a new table for the organization // @Tags tables // @Accept json // @Produce json // @Param table body contract.CreateTableRequest true "Table data" // @Success 201 {object} contract.TableResponse // @Failure 400 {object} contract.ResponseError // @Failure 401 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /tables [post] func (h *TableHandler) Create(c *gin.Context) { var req contract.CreateTableRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid request body", Message: err.Error(), }) return } organizationID := c.GetString("organization_id") orgID, err := uuid.Parse(organizationID) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid organization ID", Message: err.Error(), }) return } response, err := h.tableService.Create(c.Request.Context(), req, orgID) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to create table", Message: err.Error(), }) return } c.JSON(http.StatusCreated, response) } // GetTable godoc // @Summary Get table by ID // @Description Get table details by ID // @Tags tables // @Produce json // @Param id path string true "Table ID" // @Success 200 {object} contract.TableResponse // @Failure 400 {object} contract.ResponseError // @Failure 404 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /tables/{id} [get] func (h *TableHandler) GetByID(c *gin.Context) { id := c.Param("id") tableID, err := uuid.Parse(id) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid table ID", Message: err.Error(), }) return } response, err := h.tableService.GetByID(c.Request.Context(), tableID) if err != nil { c.JSON(http.StatusNotFound, contract.ResponseError{ Error: "Table not found", Message: err.Error(), }) return } c.JSON(http.StatusOK, response) } // UpdateTable godoc // @Summary Update table // @Description Update table details // @Tags tables // @Accept json // @Produce json // @Param id path string true "Table ID" // @Param table body contract.UpdateTableRequest true "Table update data" // @Success 200 {object} contract.TableResponse // @Failure 400 {object} contract.ResponseError // @Failure 404 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /tables/{id} [put] func (h *TableHandler) Update(c *gin.Context) { id := c.Param("id") tableID, err := uuid.Parse(id) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid table ID", Message: err.Error(), }) return } var req contract.UpdateTableRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid request body", Message: err.Error(), }) return } response, err := h.tableService.Update(c.Request.Context(), tableID, req) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to update table", Message: err.Error(), }) return } c.JSON(http.StatusOK, response) } // DeleteTable godoc // @Summary Delete table // @Description Delete table by ID // @Tags tables // @Produce json // @Param id path string true "Table ID" // @Success 204 "No Content" // @Failure 400 {object} contract.ResponseError // @Failure 404 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /tables/{id} [delete] func (h *TableHandler) Delete(c *gin.Context) { id := c.Param("id") tableID, err := uuid.Parse(id) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid table ID", Message: err.Error(), }) return } err = h.tableService.Delete(c.Request.Context(), tableID) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to delete table", Message: err.Error(), }) return } c.Status(http.StatusNoContent) } // ListTables godoc // @Summary List tables // @Description Get paginated list of tables // @Tags tables // @Produce json // @Param organization_id query string false "Organization ID" // @Param outlet_id query string false "Outlet ID" // @Param status query string false "Table status" // @Param is_active query string false "Is active" // @Param search query string false "Search term" // @Param page query int false "Page number" default(1) // @Param limit query int false "Page size" default(10) // @Success 200 {object} contract.ListTablesResponse // @Failure 400 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /tables [get] func (h *TableHandler) List(c *gin.Context) { query := contract.ListTablesQuery{ OrganizationID: c.Query("organization_id"), OutletID: c.Query("outlet_id"), Status: c.Query("status"), IsActive: c.Query("is_active"), Search: c.Query("search"), Page: 1, Limit: 10, } if pageStr := c.Query("page"); pageStr != "" { if page, err := strconv.Atoi(pageStr); err == nil && page > 0 { query.Page = page } } if limitStr := c.Query("limit"); limitStr != "" { if limit, err := strconv.Atoi(limitStr); err == nil && limit > 0 && limit <= 100 { query.Limit = limit } } response, err := h.tableService.List(c.Request.Context(), query) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to list tables", Message: err.Error(), }) return } c.JSON(http.StatusOK, response) } // OccupyTable godoc // @Summary Occupy table // @Description Occupy a table with an order // @Tags tables // @Accept json // @Produce json // @Param id path string true "Table ID" // @Param request body contract.OccupyTableRequest true "Occupy table data" // @Success 200 {object} contract.TableResponse // @Failure 400 {object} contract.ResponseError // @Failure 404 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /tables/{id}/occupy [post] func (h *TableHandler) OccupyTable(c *gin.Context) { id := c.Param("id") tableID, err := uuid.Parse(id) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid table ID", Message: err.Error(), }) return } var req contract.OccupyTableRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid request body", Message: err.Error(), }) return } response, err := h.tableService.OccupyTable(c.Request.Context(), tableID, req) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to occupy table", Message: err.Error(), }) return } c.JSON(http.StatusOK, response) } // ReleaseTable godoc // @Summary Release table // @Description Release a table and record payment amount // @Tags tables // @Accept json // @Produce json // @Param id path string true "Table ID" // @Param request body contract.ReleaseTableRequest true "Release table data" // @Success 200 {object} contract.TableResponse // @Failure 400 {object} contract.ResponseError // @Failure 404 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /tables/{id}/release [post] func (h *TableHandler) ReleaseTable(c *gin.Context) { id := c.Param("id") tableID, err := uuid.Parse(id) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid table ID", Message: err.Error(), }) return } var req contract.ReleaseTableRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid request body", Message: err.Error(), }) return } response, err := h.tableService.ReleaseTable(c.Request.Context(), tableID, req) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to release table", Message: err.Error(), }) return } c.JSON(http.StatusOK, response) } // GetAvailableTables godoc // @Summary Get available tables // @Description Get list of available tables for an outlet // @Tags tables // @Produce json // @Param outlet_id path string true "Outlet ID" // @Success 200 {array} contract.TableResponse // @Failure 400 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /outlets/{outlet_id}/tables/available [get] func (h *TableHandler) GetAvailableTables(c *gin.Context) { outletIDStr := c.Param("outlet_id") outletID, err := uuid.Parse(outletIDStr) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid outlet ID", Message: err.Error(), }) return } tables, err := h.tableService.GetAvailableTables(c.Request.Context(), outletID) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to get available tables", Message: err.Error(), }) return } c.JSON(http.StatusOK, tables) } // GetOccupiedTables godoc // @Summary Get occupied tables // @Description Get list of occupied tables for an outlet // @Tags tables // @Produce json // @Param outlet_id path string true "Outlet ID" // @Success 200 {array} contract.TableResponse // @Failure 400 {object} contract.ResponseError // @Failure 500 {object} contract.ResponseError // @Router /outlets/{outlet_id}/tables/occupied [get] func (h *TableHandler) GetOccupiedTables(c *gin.Context) { outletIDStr := c.Param("outlet_id") outletID, err := uuid.Parse(outletIDStr) if err != nil { c.JSON(http.StatusBadRequest, contract.ResponseError{ Error: "Invalid outlet ID", Message: err.Error(), }) return } tables, err := h.tableService.GetOccupiedTables(c.Request.Context(), outletID) if err != nil { c.JSON(http.StatusInternalServerError, contract.ResponseError{ Error: "Failed to get occupied tables", Message: err.Error(), }) return } c.JSON(http.StatusOK, tables) }