Refactor tender service methods for rejected tenders and enhance unit tests
continuous-integration/drone/push Build is passing

- Renamed `buildRejectedTenderIDSetForCompanies` to `buildRejectedTenderIDSetsForCompanies` to better reflect its functionality of returning a map of excluded tender IDs by company.
- Updated the implementation to return a nested map structure for better organization of excluded tender IDs per company.
- Added a new test function `TestIsRecommendedTenderExcludedForAllCompanies` to validate the visibility of tenders based on company-specific exclusions.
- Enhanced existing tests to ensure comprehensive coverage of the new logic for handling rejected tenders.

This update improves the clarity and functionality of the tender recommendation process by refining the handling of rejected tenders and expanding test coverage.
This commit is contained in:
Mazyar
2026-07-04 13:56:07 +03:30
parent 4c48e0bb3b
commit 3221a31ac8
3 changed files with 74 additions and 19 deletions
+24 -7
View File
@@ -46,15 +46,15 @@ func (s *tenderService) buildRejectedTenderIDSet(ctx context.Context, companyID
return excluded, nil
}
func (s *tenderService) buildRejectedTenderIDSetForCompanies(ctx context.Context, companyIDs []string) (map[string]struct{}, error) {
excluded := make(map[string]struct{})
func (s *tenderService) buildRejectedTenderIDSetsForCompanies(ctx context.Context, companyIDs []string) (map[string]map[string]struct{}, error) {
excludedByCompany := make(map[string]map[string]struct{})
if s.rejectedTenderLister == nil {
return excluded, nil
return excludedByCompany, nil
}
normalized := normalizeRecommendationCompanyScope(companyIDs)
if len(normalized) == 0 {
return excluded, nil
return excludedByCompany, nil
}
results := make([][]string, len(normalized))
@@ -75,11 +75,13 @@ func (s *tenderService) buildRejectedTenderIDSetForCompanies(ctx context.Context
return nil, err
}
for _, ids := range results {
addTenderIDsToSet(excluded, ids)
for i, companyID := range normalized {
excluded := make(map[string]struct{})
addTenderIDsToSet(excluded, results[i])
excludedByCompany[companyID] = excluded
}
return excluded, nil
return excludedByCompany, nil
}
func addTenderIDsToSet(set map[string]struct{}, ids []string) {
@@ -117,3 +119,18 @@ func isRecommendedTenderExcluded(tender Tender, tenderRef string, excluded map[s
return false
}
func isRecommendedTenderExcludedForAllCompanies(tender Tender, tenderRef string, excludedByCompany map[string]map[string]struct{}, companyIDs []string) bool {
normalized := normalizeRecommendationCompanyScope(companyIDs)
if len(normalized) == 0 {
return false
}
for _, companyID := range normalized {
if !isRecommendedTenderExcluded(tender, tenderRef, excludedByCompany[companyID]) {
return false
}
}
return true
}
+39 -8
View File
@@ -71,7 +71,7 @@ func TestIsRecommendedTenderExcluded(t *testing.T) {
}
}
func TestBuildRejectedTenderIDSetForCompanies(t *testing.T) {
func TestBuildRejectedTenderIDSetsForCompanies(t *testing.T) {
service := &tenderService{
rejectedTenderLister: stubRejectedTenderLister{
byCompany: map[string][]string{
@@ -81,17 +81,48 @@ func TestBuildRejectedTenderIDSetForCompanies(t *testing.T) {
},
}
got, err := service.buildRejectedTenderIDSetForCompanies(context.Background(), []string{"company-a", "company-b", "company-a"})
got, err := service.buildRejectedTenderIDSetsForCompanies(context.Background(), []string{"company-a", "company-b", "company-a"})
if err != nil {
t.Fatalf("buildRejectedTenderIDSetForCompanies() error = %v", err)
t.Fatalf("buildRejectedTenderIDSetsForCompanies() error = %v", err)
}
for _, tenderID := range []string{"tender-1", "tender-2", "tender-3"} {
if _, ok := got[tenderID]; !ok {
t.Fatalf("expected excluded set to contain %q", tenderID)
if _, ok := got["company-a"]["tender-1"]; !ok {
t.Fatalf("expected company-a exclusions to contain tender-1")
}
if _, ok := got["company-a"]["tender-2"]; !ok {
t.Fatalf("expected company-a exclusions to contain tender-2")
}
if len(got) != 3 {
t.Fatalf("buildRejectedTenderIDSetForCompanies() len = %d, want 3", len(got))
if _, ok := got["company-b"]["tender-2"]; !ok {
t.Fatalf("expected company-b exclusions to contain tender-2")
}
if _, ok := got["company-b"]["tender-3"]; !ok {
t.Fatalf("expected company-b exclusions to contain tender-3")
}
if len(got) != 2 {
t.Fatalf("buildRejectedTenderIDSetsForCompanies() len = %d, want 2", len(got))
}
}
func TestIsRecommendedTenderExcludedForAllCompanies(t *testing.T) {
tender := Tender{
Model: mongo.Model{},
ContractFolderID: "055329e0-3d8f-4eeb-946a-85a451f2e36b",
NoticePublicationID: "00423458-2026",
}
tender.ID, _ = bson.ObjectIDFromHex("507f1f77bcf86cd799439011")
procRef := FormatAIProcedureRef(tender.ContractFolderID, tender.NoticePublicationID)
excludedByCompany := map[string]map[string]struct{}{
"company-a": {procRef: {}},
"company-b": {},
}
if isRecommendedTenderExcludedForAllCompanies(tender, procRef, excludedByCompany, []string{"company-a", "company-b"}) {
t.Fatalf("expected tender to remain visible when not all companies rejected it")
}
excludedByCompany["company-b"][procRef] = struct{}{}
if !isRecommendedTenderExcludedForAllCompanies(tender, procRef, excludedByCompany, []string{"company-a", "company-b"}) {
t.Fatalf("expected tender to be hidden when all companies rejected it")
}
}
+10 -3
View File
@@ -973,10 +973,13 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat
return nil, err
}
var excluded map[string]struct{}
var (
excluded map[string]struct{}
excludedByCompany map[string]map[string]struct{}
)
if form.ExcludeRejectedTenders {
if len(companyIDs) > 0 {
excluded, err = s.buildRejectedTenderIDSetForCompanies(ctx, companyIDs)
excludedByCompany, err = s.buildRejectedTenderIDSetsForCompanies(ctx, companyIDs)
} else {
excluded, err = s.buildRejectedTenderIDSet(ctx, companyID)
}
@@ -999,7 +1002,11 @@ func (s *tenderService) Recommend(ctx context.Context, form *SearchForm, paginat
if !ok {
continue
}
if isRecommendedTenderExcluded(tender, tenderRef, excluded) {
if len(companyIDs) > 0 {
if isRecommendedTenderExcludedForAllCompanies(tender, tenderRef, excludedByCompany, companyIDs) {
continue
}
} else if isRecommendedTenderExcluded(tender, tenderRef, excluded) {
continue
}
if form.OnlyActiveDeadlines && !tender.IsRecommendable(now) {