61a217cf09
- Added new query parameters `created_from` and `created_to` to the tender approval endpoints for filtering by creation date using Unix timestamps. - Updated the `GetByCompanyID` method in the repository and service layers to support the new filtering options. - Modified the handler methods to parse and pass the new parameters, improving the flexibility of tender approval retrieval. - Updated API documentation to reflect the new query parameters, ensuring clarity for API consumers.
404 lines
17 KiB
Go
404 lines
17 KiB
Go
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(submitted, rejected)"
|
|
// @Param created_from query integer false "Filter by created date from (Unix timestamp)"
|
|
// @Param created_to query integer false "Filter by created date to (Unix timestamp)"
|
|
// @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 != ApprovalStatusSubmitted && statusVal != ApprovalStatusRejected {
|
|
return response.BadRequest(c, "Invalid status value", "Must be 'submitted' or 'rejected'")
|
|
}
|
|
status = &statusVal
|
|
}
|
|
|
|
var from *int64
|
|
if fromParam := c.QueryParam("created_from"); fromParam != "" {
|
|
if parsed, err := strconv.ParseInt(fromParam, 10, 64); err == nil {
|
|
from = &parsed
|
|
}
|
|
}
|
|
|
|
var to *int64
|
|
if toParam := c.QueryParam("created_to"); toParam != "" {
|
|
if parsed, err := strconv.ParseInt(toParam, 10, 64); err == nil {
|
|
to = &parsed
|
|
}
|
|
}
|
|
|
|
tenderApprovalsWithTender, err := h.service.GetTenderApprovalsByCompanyIDWithTender(c.Request().Context(), companyID, submissionMode, status, from, to)
|
|
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 (submitted, rejected)
|
|
// @Tags Admin-TenderApprovals
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param status path string true "Tender approval status" Enums(submitted, 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 != ApprovalStatusSubmitted && status != ApprovalStatusRejected {
|
|
return response.BadRequest(c, "Invalid tender approval status", "Must be submitted 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")
|
|
}
|