Files
tm_back/internal/tender_approval/handler.go
T
n.nakhostin 61a217cf09 Enhance Tender Approval Filtering with Created Date Parameters
- 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.
2025-09-03 10:23:47 +03:30

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")
}