Enhance tender service to exclude company-rejected tenders from recommendations

- Updated the tender service to include a new dependency for listing rejected tenders by company, allowing for more refined tender recommendations.
- Introduced a new field in the SearchForm to specify whether to exclude rejected tenders from the recommendation results.
- Enhanced the Recommend method to filter out rejected tenders based on the new exclusion logic, improving the relevance of AI-ranked tender recommendations.
- Added unit tests to verify the exclusion logic for rejected tenders, ensuring robust functionality.

This update improves the tender recommendation process by ensuring that company-rejected tenders are not included in the results, enhancing user experience and satisfaction.
This commit is contained in:
Mazyar
2026-07-03 19:55:01 +03:30
parent ec7db8b9f0
commit fe3a71ba2b
8 changed files with 212 additions and 21 deletions
+41 -15
View File
@@ -80,13 +80,14 @@ type Service interface {
// tenderService implements TenderService interface
type tenderService struct {
repository TenderRepository
companyService company.Service
customerService customer.Service
logger logger.Logger
aiSummarizerClient AISummarizerClient
aiSummarizerStorage AISummarizerStorage
defaultLanguage string
repository TenderRepository
companyService company.Service
customerService customer.Service
rejectedTenderLister CompanyRejectedTenderLister
logger logger.Logger
aiSummarizerClient AISummarizerClient
aiSummarizerStorage AISummarizerStorage
defaultLanguage string
}
const (
@@ -100,19 +101,29 @@ var (
)
// NewService creates a new tender service
func NewService(repository TenderRepository, companyService company.Service, customerService customer.Service, logger logger.Logger, aiClient AISummarizerClient, aiStorage AISummarizerStorage, defaultLanguage string) Service {
func NewService(
repository TenderRepository,
companyService company.Service,
customerService customer.Service,
rejectedTenderLister CompanyRejectedTenderLister,
logger logger.Logger,
aiClient AISummarizerClient,
aiStorage AISummarizerStorage,
defaultLanguage string,
) Service {
if strings.TrimSpace(defaultLanguage) == "" {
defaultLanguage = "en"
}
return &tenderService{
repository: repository,
companyService: companyService,
customerService: customerService,
logger: logger,
aiSummarizerClient: aiClient,
aiSummarizerStorage: aiStorage,
defaultLanguage: strings.ToLower(defaultLanguage),
repository: repository,
companyService: companyService,
customerService: customerService,
rejectedTenderLister: rejectedTenderLister,
logger: logger,
aiSummarizerClient: aiClient,
aiSummarizerStorage: aiStorage,
defaultLanguage: strings.ToLower(defaultLanguage),
}
}
@@ -946,6 +957,18 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat
return nil, err
}
var excluded map[string]struct{}
if form.ExcludeRejectedTenders {
excluded, err = s.buildRejectedTenderIDSet(ctx, companyID)
if err != nil {
s.logger.Error("Failed to build recommendation exclusions", map[string]interface{}{
"company_id": companyID,
"error": err.Error(),
})
return nil, fmt.Errorf("failed to build recommendation exclusions: %w", err)
}
}
lang := s.pickResponseLanguage(form.Language)
now := time.Now().Unix()
ordered := make([]TenderResponse, 0, len(recommendations))
@@ -955,6 +978,9 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat
if !ok {
continue
}
if isRecommendedTenderExcluded(tender, tenderRef, excluded) {
continue
}
if form.OnlyActiveDeadlines && !tender.IsRecommendable(now) {
continue
}