From ff6bdfcb093847b26abde94c087f76c8073c24fe Mon Sep 17 00:00:00 2001 From: Mazyar Date: Tue, 30 Jun 2026 17:22:06 +0330 Subject: [PATCH] Add IsRecommendable method and corresponding tests for Tender entity - Implemented the IsRecommendable method in the Tender entity to determine if a tender should be included in AI recommendations based on its status and deadline. - Added unit tests for the IsRecommendable method to cover various scenarios, ensuring accurate recommendation logic. - Updated the Recommend method in the tender service to utilize the new IsRecommendable method for improved clarity and functionality. This update enhances the recommendation logic for tenders, ensuring only appropriate tenders are considered for AI recommendations based on their status and deadlines. --- internal/tender/entity.go | 13 ++++++++- internal/tender/entity_test.go | 49 ++++++++++++++++++++++++++++++++++ internal/tender/service.go | 13 +++++++-- 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/internal/tender/entity.go b/internal/tender/entity.go index 62cbbdf..37b34aa 100644 --- a/internal/tender/entity.go +++ b/internal/tender/entity.go @@ -262,11 +262,22 @@ func (t *Tender) IsExpired() bool { return false } - // Check if deadline (in milliseconds) is in the past now := time.Now().Unix() return t.TenderDeadline < now } +// IsRecommendable reports whether a tender should appear in AI recommendation results. +func (t *Tender) IsRecommendable(now int64) bool { + switch t.Status { + case TenderStatusExpired, TenderStatusCancelled, TenderStatusAwarded, TenderStatusClosed: + return false + } + if t.TenderDeadline <= now { + return false + } + return true +} + // GetTenderURL returns the TED tender URL func (t *Tender) GetTenderURL() string { if t.TenderURL != "" { diff --git a/internal/tender/entity_test.go b/internal/tender/entity_test.go index 72ec624..6e8e571 100644 --- a/internal/tender/entity_test.go +++ b/internal/tender/entity_test.go @@ -72,3 +72,52 @@ func TestResolvedEstimatedValueAndCurrencyPrefersTopLevel(t *testing.T) { t.Fatalf("expected USD, got %q", currency) } } + +func TestTenderIsRecommendable(t *testing.T) { + now := int64(1_700_000_000) + + tests := []struct { + name string + tender Tender + want bool + }{ + { + name: "active with future deadline", + tender: Tender{Status: TenderStatusActive, TenderDeadline: now + 3600}, + want: true, + }, + { + name: "active with past deadline", + tender: Tender{Status: TenderStatusActive, TenderDeadline: now - 3600}, + want: false, + }, + { + name: "active with deadline at now", + tender: Tender{Status: TenderStatusActive, TenderDeadline: now}, + want: false, + }, + { + name: "active without deadline", + tender: Tender{Status: TenderStatusActive, TenderDeadline: 0}, + want: false, + }, + { + name: "expired status with future deadline", + tender: Tender{Status: TenderStatusExpired, TenderDeadline: now + 3600}, + want: false, + }, + { + name: "awarded with future deadline", + tender: Tender{Status: TenderStatusAwarded, TenderDeadline: now + 3600}, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.tender.IsRecommendable(now); got != tt.want { + t.Fatalf("IsRecommendable() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/tender/service.go b/internal/tender/service.go index d741622..e2764c0 100644 --- a/internal/tender/service.go +++ b/internal/tender/service.go @@ -955,10 +955,10 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat if !ok { continue } - if form.OnlyActiveDeadlines && tender.TenderDeadline <= now { + if form.OnlyActiveDeadlines && !tender.IsRecommendable(now) { continue } - if len(form.Status) > 0 && tender.Status != TenderStatusActive { + if len(form.Status) > 0 && !statusAllowed(tender.Status, form.Status) { continue } @@ -985,6 +985,15 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat }, nil } +func statusAllowed(status TenderStatus, allowed []string) bool { + for _, s := range allowed { + if string(status) == strings.TrimSpace(s) { + return true + } + } + return false +} + // Delete deletes a tender // GetTenderStatistics retrieves tender statistics