Enhance document scraper service with AI portal integration and error handling

- Updated the document scraper service to include a new ScrapePortalsProvider interface, allowing for dynamic retrieval of supported scraping portals.
- Modified the ListPendingTenders and GetTenderByNoticeID methods to filter tenders based on document URLs that match the configured portals.
- Introduced new error handling for cases when the scrape portals provider is not configured, returning appropriate service unavailable responses.
- Enhanced API documentation to reflect changes in tender retrieval logic and added error response details for unsupported portal scenarios.

This update improves the document scraping functionality by integrating AI portal support, enhancing the overall reliability and flexibility of the tender management system.
This commit is contained in:
Mazyar
2026-06-21 09:58:11 +03:30
parent 550f11a77e
commit 45cfa24a72
7 changed files with 143 additions and 45 deletions
+27 -5
View File
@@ -557,7 +557,7 @@ func (r *tenderRepository) GetExpiredTenders(ctx context.Context, beforeDate int
// PendingDocumentScrapeFilter defines query criteria for pending document scrape tenders.
type PendingDocumentScrapeFilter struct {
CountryCodes []string
Portals []string
MinDeadline *int64 // when set, tender_deadline must be greater than this value
CreatedAtFrom *int64
CreatedAtTo *int64
@@ -565,17 +565,39 @@ type PendingDocumentScrapeFilter struct {
Skip int
}
// GetPendingDocumentScrapeTenders returns unscraped tenders for the given countries.
func scrapePortalURLFilter(portals []string) bson.M {
conditions := make([]bson.M, 0, len(portals)*2)
for _, portal := range portals {
portal = strings.TrimSpace(portal)
if portal == "" {
continue
}
regex := bson.M{"$regex": regexp.QuoteMeta(portal), "$options": "i"}
conditions = append(conditions,
bson.M{"document_uri": regex},
bson.M{"tender_url": regex},
)
}
if len(conditions) == 0 {
return nil
}
return bson.M{"$or": conditions}
}
// GetPendingDocumentScrapeTenders returns unscraped tenders whose document URL matches a supported portal.
// When MinDeadline is set, only tenders with tender_deadline greater than that value are returned.
func (r *tenderRepository) GetPendingDocumentScrapeTenders(ctx context.Context, filter PendingDocumentScrapeFilter) ([]Tender, bool, error) {
if len(filter.CountryCodes) == 0 {
portalFilter := scrapePortalURLFilter(filter.Portals)
if portalFilter == nil {
return nil, false, nil
}
query := bson.M{
"country_code": bson.M{"$in": filter.CountryCodes},
"processing_metadata.documents_scraped": bson.M{"$ne": true},
}
for key, value := range portalFilter {
query[key] = value
}
if filter.MinDeadline != nil {
query["tender_deadline"] = bson.M{
@@ -606,7 +628,7 @@ func (r *tenderRepository) GetPendingDocumentScrapeTenders(ctx context.Context,
result, err := r.ormRepo.FindAll(ctx, query, pagination)
if err != nil {
r.logger.Error("Failed to get pending document scrape tenders", map[string]interface{}{
"country_codes": filter.CountryCodes,
"portals": filter.Portals,
"min_deadline": filter.MinDeadline,
"created_at_from": filter.CreatedAtFrom,
"created_at_to": filter.CreatedAtTo,