Enhance Tender API with New Recommendation Endpoint and Route Updates

- Updated the tender API to include a new endpoint for recommending public tenders based on company profiles, enhancing user experience for mobile application users.
- Modified existing routes to reflect the new structure, changing the tender details route and adding a dedicated recommendation route.
- Improved Swagger documentation to accurately represent the new endpoint, including detailed descriptions, parameters, and response formats.
- Ensured adherence to Clean Architecture principles by maintaining clear separation of concerns in the service and handler layers.
This commit is contained in:
n.nakhostin
2025-08-17 08:40:28 +03:30
parent e986ee4135
commit 4663a9781e
8 changed files with 333 additions and 20 deletions
+52 -7
View File
@@ -3,6 +3,7 @@ package tender
import (
"context"
"fmt"
"math"
"time"
"tm/internal/company"
"tm/pkg/logger"
@@ -16,6 +17,7 @@ type TenderService interface {
UpdateTender(ctx context.Context, req UpdateTenderRequest) (*Tender, error)
DeleteTender(ctx context.Context, id string) error
ListTenders(ctx context.Context, req ListTendersRequest) (*ListTendersResponse, error)
RecommendTenders(ctx context.Context, companyID *string, limit, offset int) (*ListTendersResponse, error)
// Maintenance operations
UpdateExpiredTenders(ctx context.Context) error
@@ -128,13 +130,6 @@ func (s *tenderService) DeleteTender(ctx context.Context, id string) error {
return nil
}
// TenderWithMatch represents a tender with calculated match percentage for sorting
type TenderWithMatch struct {
Tender *Tender
MatchPercentage int
DaysUntilDeadline int
}
// ListTenders retrieves tenders with pagination and filtering
func (s *tenderService) ListTenders(ctx context.Context, req ListTendersRequest) (*ListTendersResponse, error) {
s.logger.Info("Listing tenders", map[string]interface{}{
@@ -224,6 +219,56 @@ func (s *tenderService) ListTenders(ctx context.Context, req ListTendersRequest)
}, nil
}
// ListTenders retrieves tenders with pagination and filtering
func (s *tenderService) RecommendTenders(ctx context.Context, companyID *string, limit, offset int) (*ListTendersResponse, error) {
s.logger.Info("Recommend tenders", map[string]interface{}{
"company_id": companyID,
})
if limit <= 0 {
limit = 20
}
if limit > 100 {
limit = 100
}
company, err := s.companyService.GetCompanyByID(ctx, *companyID)
if err != nil {
s.logger.Error("Failed to get company", map[string]interface{}{
"company_id": *companyID,
"error": err.Error(),
})
return nil, fmt.Errorf("failed to get company: %w", err)
}
tenders, total, err := s.repository.List(ctx, TenderSearchCriteria{
Status: []TenderStatus{TenderStatusActive},
Classifications: company.Tags.CPVCodes,
}, limit, offset)
if err != nil {
s.logger.Error("Failed to list tenders", map[string]interface{}{
"error": err.Error(),
})
return nil, fmt.Errorf("failed to list tenders: %w", err)
}
tenderResponses := make([]TenderResponse, 0, len(tenders))
for _, tender := range tenders {
tenderResponses = append(tenderResponses, *tender.ToTenderResponse())
}
return &ListTendersResponse{
Tenders: tenderResponses,
Metadata: &response.Meta{
Total: int(total),
Limit: limit,
Offset: offset,
Pages: int(math.Ceil(float64(total) / float64(limit))),
Page: int(math.Ceil(float64(offset) / float64(limit))),
},
}, nil
}
// GetTenderStatistics retrieves tender statistics
func (s *tenderService) GetTenderStatistics(ctx context.Context) (*TenderStatistics, error) {
s.logger.Info("Retrieving tender statistics", map[string]interface{}{})