package tender_approval import ( "strconv" "tm/pkg/logger" "tm/pkg/response" "github.com/labstack/echo/v4" ) // Handler handles HTTP requests for tender approval operations type Handler struct { service Service logger logger.Logger } // NewHandler creates a new tender approval handler func NewHandler(service Service, logger logger.Logger) *Handler { return &Handler{ service: service, logger: logger, } } // CreateTenderApproval creates a new tender approval // @Summary Create a new tender approval // @Description Create a new tender approval for a company to approve or reject a tender // @Tags TenderApprovals // @Accept json // @Produce json // @Param tender_approval body CreateTenderApprovalForm true "Tender approval information" // @Success 201 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval created successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid input data" // @Failure 409 {object} response.APIResponse "Conflict - Tender approval already exists for this tender and company" // @Failure 422 {object} response.APIResponse "Validation error - Invalid request data" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /api/v1/tender-approvals [post] func (h *Handler) ToggleTenderApproval(c echo.Context) error { form, err := response.Parse[ToggleTenderApprovalForm](c) if err != nil { return response.ValidationError(c, "Invalid request data", err.Error()) } // Get company ID from context companyID := c.Get("company_id").(string) if companyID == "" { return response.Unauthorized(c, "Unauthorized") } tenderApproval, err := h.service.ToggleTenderApproval(c.Request().Context(), form, companyID) if err != nil { if err.Error() == "tender approval already exists for this tender and company" { return response.Conflict(c, err.Error()) } return response.InternalServerError(c, "Failed to create tender approval") } return response.Success(c, tenderApproval, "Tender approval updated successfully") } // GetTenderApproval retrieves a tender approval by ID // @Summary Get tender approval by ID // @Description Retrieve detailed tender approval information by ID // @Tags TenderApprovals // @Accept json // @Produce json // @Param id path string true "Tender Approval ID" // @Success 200 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval ID" // @Failure 404 {object} response.APIResponse "Not found - Tender approval not found" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /api/v1/tender-approvals/{id} [get] func (h *Handler) GetPublicTenderApproval(c echo.Context) error { id := c.Param("id") // Get the approval with tender details tenderApprovalWithTender, err := h.service.GetTenderApprovalByIDWithTender(c.Request().Context(), id) if err != nil { if err.Error() == "tender approval not found" { return response.NotFound(c, "Tender approval not found") } return response.InternalServerError(c, "Failed to get tender approval") } return response.Success(c, tenderApprovalWithTender, "Tender approval retrieved successfully") } // GetTenderApprovalByTenderAndCompany retrieves a tender approval by tender ID and company ID // @Summary Get tender approval by tender and company // @Description Retrieve tender approval information for a specific tender and company combination // @Tags TenderApprovals // @Accept json // @Produce json // @Param tender_id path string true "Tender ID" // @Success 200 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid tender ID or company ID" // @Failure 404 {object} response.APIResponse "Not found - Tender approval not found" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /api/v1/tender-approvals/tender/{tender_id} [get] func (h *Handler) GetTenderApprovalByTenderAndCompany(c echo.Context) error { companyID := c.Get("company_id").(string) if companyID == "" { return response.Unauthorized(c, "Unauthorized") } tenderID := c.Param("tender_id") if tenderID == "" { return response.BadRequest(c, "Missing required parameters", "tender_id required") } tenderApprovalWithTender, err := h.service.GetTenderApprovalByTenderAndCompanyWithTender(c.Request().Context(), tenderID, companyID) if err != nil { if err.Error() == "tender approval not found" { return response.NotFound(c, "Tender approval not found") } return response.InternalServerError(c, "Failed to get tender approval") } return response.Success(c, tenderApprovalWithTender, "Tender approval retrieved successfully") } // GetTenderApprovalsByCompanyID retrieves all tender approvals for a specific company // @Summary Get tender approvals by company ID // @Description Retrieve all tender approvals for a specific company with optional filtering // @Tags TenderApprovals // @Accept json // @Produce json // @Param submission_mode query string false "Filter by submission mode Enums(self-apply, partnership)" // @Param status query string false "Filter by status Enums(approved, rejected)" // @Success 200 {object} response.APIResponse{data=[]TenderApprovalWithTenderResponse} "Tender approvals retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid company ID" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /api/v1/tender-approvals [get] func (h *Handler) PublicGetTenderApprovals(c echo.Context) error { companyID := c.Get("company_id").(string) if companyID == "" { return response.Unauthorized(c, "Unauthorized") } // Get query parameters for filtering submissionModeStr := c.QueryParam("submission_mode") statusStr := c.QueryParam("status") // Parse submission mode filter var submissionMode *SubmissionMode if submissionModeStr != "" { mode := SubmissionMode(submissionModeStr) if mode != SubmissionModeSelfApply && mode != SubmissionModePartnership { return response.BadRequest(c, "Invalid submission_mode value", "Must be 'self-apply' or 'partnership'") } submissionMode = &mode } // Parse status filter var status *ApprovalStatus if statusStr != "" { statusVal := ApprovalStatus(statusStr) if statusVal != ApprovalStatusApproved && statusVal != ApprovalStatusRejected { return response.BadRequest(c, "Invalid status value", "Must be 'approved' or 'rejected'") } status = &statusVal } tenderApprovalsWithTender, err := h.service.GetTenderApprovalsByCompanyIDWithTender(c.Request().Context(), companyID, submissionMode, status) if err != nil { return response.InternalServerError(c, "Failed to get tender approvals") } return response.Success(c, tenderApprovalsWithTender, "Tender approvals retrieved successfully") } // **************** Admin Routes **************** // ListTenderApprovals lists tender approvals with filters and pagination // @Summary List tender approvals with filters and pagination // @Description Retrieve a paginated list of tender approvals with filtering options // @Tags Admin-TenderApprovals // @Accept json // @Produce json // @Param tender_id query string false "Filter by tender ID" // @Param company_id query string false "Filter by company ID" // @Param status query array false "Filter by status" // @Param submission_mode query array false "Filter by submission mode" // @Param created_at_from query integer false "Filter by creation date from (Unix timestamp)" // @Param created_at_to query integer false "Filter by creation date to (Unix timestamp)" // @Param limit query integer false "Number of approvals per page (1-100)" minimum(1) maximum(100) default(20) // @Param offset query integer false "Number of approvals to skip for pagination" minimum(0) default(0) // @Param sort_by query string false "Field to sort by" Enums(created_at, updated_at, status, submission_mode) default(created_at) // @Param sort_order query string false "Sort order" Enums(asc, desc) default(desc) // @Success 200 {object} response.APIResponse{data=TenderApprovalListResponse} "Tender approvals retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid query parameters" // @Failure 422 {object} response.APIResponse "Validation error - Invalid query parameters" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /admin/v1/tender-approvals [get] func (h *Handler) ListTenderApprovals(c echo.Context) error { form, err := response.Parse[ListTenderApprovalsForm](c) if err != nil { return response.ValidationError(c, "Invalid request data", err.Error()) } result, err := h.service.ListTenderApprovalsWithTender(c.Request().Context(), form) if err != nil { return response.InternalServerError(c, "Failed to list tender approvals") } return response.Success(c, result, "Tender approvals retrieved successfully") } // GetTenderApprovalStats returns tender approval statistics // @Summary Get tender approval statistics // @Description Get comprehensive tender approval statistics for dashboard // @Tags Admin-TenderApprovals // @Accept json // @Produce json // @Success 200 {object} response.APIResponse{data=TenderApprovalStatsResponse} "Tender approval statistics retrieved successfully" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /admin/v1/tender-approvals/stats [get] func (h *Handler) GetTenderApprovalStats(c echo.Context) error { stats, err := h.service.GetTenderApprovalStats(c.Request().Context()) if err != nil { return response.InternalServerError(c, "Failed to get tender approval statistics") } return response.Success(c, stats, "Tender approval statistics retrieved successfully") } // GetCompanyTenderApprovalStats returns company-specific tender approval statistics // @Summary Get company tender approval statistics // @Description Get comprehensive tender approval statistics for a specific company // @Tags TenderApprovals // @Accept json // @Produce json // @Success 200 {object} response.APIResponse{data=CompanyTenderApprovalStatsResponse} "Company tender approval statistics retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid company ID" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /api/v1/tender-approvals/stats [get] func (h *Handler) GetCompanyTenderApprovalStats(c echo.Context) error { companyID := c.Get("company_id").(string) if companyID == "" { return response.Unauthorized(c, "Unauthorized") } stats, err := h.service.GetCompanyTenderApprovalStats(c.Request().Context(), companyID) if err != nil { return response.InternalServerError(c, "Failed to get company tender approval statistics") } return response.Success(c, stats, "Company tender approval statistics retrieved successfully") } // GetTenderApprovalsByStatus retrieves tender approvals by status // @Summary Get tender approvals by status // @Description Retrieve tender approvals filtered by their status (approved, rejected) // @Tags Admin-TenderApprovals // @Accept json // @Produce json // @Param status path string true "Tender approval status" Enums(approved, rejected) // @Param limit query integer false "Number of approvals per page (1-100)" minimum(1) maximum(100) default(20) // @Param offset query integer false "Number of approvals to skip for pagination" minimum(0) default(0) // @Success 200 {object} response.APIResponse{data=[]TenderApprovalResponse,meta=response.Meta} "Tender approvals retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval status" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /admin/v1/tender-approvals/status/{status} [get] func (h *Handler) GetTenderApprovalsByStatus(c echo.Context) error { statusStr := c.Param("status") status := ApprovalStatus(statusStr) // Validate status if status != ApprovalStatusApproved && status != ApprovalStatusRejected { return response.BadRequest(c, "Invalid tender approval status", "Must be approved or rejected") } limit := 20 if limitStr := c.QueryParam("limit"); limitStr != "" { if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 && parsedLimit <= 100 { limit = parsedLimit } } offset := 0 if offsetStr := c.QueryParam("offset"); offsetStr != "" { if parsedOffset, err := strconv.Atoi(offsetStr); err == nil && parsedOffset >= 0 { offset = parsedOffset } } tenderApprovalsWithTender, total, err := h.service.GetTenderApprovalsByStatusWithTender(c.Request().Context(), status, limit, offset) if err != nil { return response.InternalServerError(c, "Failed to retrieve tender approvals by status") } meta := &response.Meta{ Total: int(total), Limit: limit, Offset: offset, } return response.SuccessWithMeta(c, tenderApprovalsWithTender, meta, "Tender approvals retrieved successfully") } // GetTenderApprovalsBySubmissionMode retrieves tender approvals by submission mode // @Summary Get tender approvals by submission mode // @Description Retrieve tender approvals filtered by their submission mode (self-apply, partnership) // @Tags Admin-TenderApprovals // @Accept json // @Produce json // @Param submission_mode path string true "Tender approval submission mode" Enums(self-apply, partnership) // @Param limit query integer false "Number of approvals per page (1-100)" minimum(1) maximum(100) default(20) // @Param offset query integer false "Number of approvals to skip for pagination" minimum(0) default(0) // @Success 200 {object} response.APIResponse{data=[]TenderApprovalResponse,meta=response.Meta} "Tender approvals retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval submission mode" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /admin/v1/tender-approvals/submission-mode/{submission_mode} [get] func (h *Handler) GetTenderApprovalsBySubmissionMode(c echo.Context) error { submissionModeStr := c.Param("submission_mode") submissionMode := SubmissionMode(submissionModeStr) // Validate submission mode if submissionMode != SubmissionModeSelfApply && submissionMode != SubmissionModePartnership { return response.BadRequest(c, "Invalid tender approval submission mode", "Must be self-apply or partnership") } limit := 20 if limitStr := c.QueryParam("limit"); limitStr != "" { if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 && parsedLimit <= 100 { limit = parsedLimit } } offset := 0 if offsetStr := c.QueryParam("offset"); offsetStr != "" { if parsedOffset, err := strconv.Atoi(offsetStr); err == nil && parsedOffset >= 0 { offset = parsedOffset } } tenderApprovalsWithTender, total, err := h.service.GetTenderApprovalsBySubmissionModeWithTender(c.Request().Context(), submissionMode, limit, offset) if err != nil { return response.InternalServerError(c, "Failed to retrieve tender approvals by submission mode") } meta := &response.Meta{ Total: int(total), Limit: limit, Offset: offset, } return response.SuccessWithMeta(c, tenderApprovalsWithTender, meta, "Tender approvals retrieved successfully") } // GetTenderApproval retrieves a tender approval by ID // @Summary Get tender approval by ID // @Description Retrieve detailed tender approval information by ID // @Tags Admin-TenderApprovals // @Accept json // @Produce json // @Param id path string true "Tender Approval ID" // @Success 200 {object} response.APIResponse{data=TenderApprovalResponse} "Tender approval retrieved successfully" // @Failure 400 {object} response.APIResponse "Bad request - Invalid tender approval ID" // @Failure 404 {object} response.APIResponse "Not found - Tender approval not found" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security BearerAuth // @Router /admin/v1/tender-approvals/{id} [get] func (h *Handler) GetTenderApproval(c echo.Context) error { id := c.Param("id") // Get the approval with tender details tenderApprovalWithTender, err := h.service.GetTenderApprovalByIDWithTender(c.Request().Context(), id) if err != nil { if err.Error() == "tender approval not found" { return response.NotFound(c, "Tender approval not found") } return response.InternalServerError(c, "Failed to get tender approval") } return response.Success(c, tenderApprovalWithTender, "Tender approval retrieved successfully") }