package workers import ( "context" "tm/internal/notice" "tm/internal/tender" "tm/pkg/logger" "tm/pkg/mongo" "tm/pkg/notification" "tm/pkg/ollama" ) type NoticeWorker struct { Mongo *mongo.ConnectionManager Logger logger.Logger Notify notification.SDK Ollama *ollama.SDK NoticeRepo notice.Repository TenderRepo tender.TenderRepository } func NewNoticeWorker(mongo *mongo.ConnectionManager, logger logger.Logger, notify notification.SDK, noticeRepo notice.Repository, tenderRepo tender.TenderRepository) *NoticeWorker { return &NoticeWorker{ Mongo: mongo, Logger: logger, Notify: notify, NoticeRepo: noticeRepo, TenderRepo: tenderRepo, } } func (w *NoticeWorker) Run() { w.Logger.Info("Notice worker started", map[string]interface{}{}) limit := 10 skip := 0 for { notices, _, err := w.NoticeRepo.GetUnProcessedNotices(context.Background(), limit, skip) if err != nil { w.Logger.Error("Failed to get notices", map[string]interface{}{ "error": err.Error(), }) continue } if len(notices) == 0 { break } for _, n := range notices { w.Logger.Info("Notice", map[string]interface{}{ "notice": n.ID.Hex(), }) t, err := w.TenderRepo.GetByNoticePublicationID(context.Background(), n.NoticePublicationID) if err == nil { continue } err = w.ToTender(&n, t) if err != nil { w.Logger.Error("Failed to create tender", map[string]interface{}{ "error": err.Error(), }) continue } if t.ID.IsZero() { err = w.TenderRepo.Create(context.Background(), t) if err != nil { w.Logger.Error("Failed to create tender", map[string]interface{}{ "error": err.Error(), }) } } else { err = w.TenderRepo.Update(context.Background(), t) if err != nil { w.Logger.Error("Failed to update tender", map[string]interface{}{ "error": err.Error(), }) } } } skip += limit } } func (w *NoticeWorker) ToTender(n *notice.Notice, t *tender.Tender) error { // Buyer Organization buyerOrg := &tender.Organization{} if n.BuyerOrganization != nil { buyerOrg = &tender.Organization{ Name: n.BuyerOrganization.Name, CompanyID: n.BuyerOrganization.CompanyID, WebsiteURI: n.BuyerOrganization.WebsiteURI, ContactName: n.BuyerOrganization.ContactName, ContactTelephone: n.BuyerOrganization.ContactTelephone, ContactEmail: n.BuyerOrganization.ContactEmail, ContactFax: n.BuyerOrganization.ContactFax, Role: n.BuyerOrganization.Role, Address: tender.Address{ StreetName: n.BuyerOrganization.Address.StreetName, CityName: n.BuyerOrganization.Address.CityName, PostalZone: n.BuyerOrganization.Address.PostalZone, CountrySubentityCode: n.BuyerOrganization.Address.CountrySubentityCode, Department: n.BuyerOrganization.Address.Department, Region: n.BuyerOrganization.Address.Region, CountryCode: n.BuyerOrganization.Address.CountryCode, }, } } // Review Organization reviewOrg := &tender.Organization{} if n.ReviewOrganization != nil { reviewOrg = &tender.Organization{ Name: n.ReviewOrganization.Name, CompanyID: n.ReviewOrganization.CompanyID, WebsiteURI: n.ReviewOrganization.WebsiteURI, ContactName: n.ReviewOrganization.ContactName, ContactTelephone: n.ReviewOrganization.ContactTelephone, ContactEmail: n.ReviewOrganization.ContactEmail, ContactFax: n.ReviewOrganization.ContactFax, Role: n.ReviewOrganization.Role, Address: tender.Address{ StreetName: n.ReviewOrganization.Address.StreetName, CityName: n.ReviewOrganization.Address.CityName, PostalZone: n.ReviewOrganization.Address.PostalZone, CountrySubentityCode: n.ReviewOrganization.Address.CountrySubentityCode, Department: n.ReviewOrganization.Address.Department, Region: n.ReviewOrganization.Address.Region, CountryCode: n.ReviewOrganization.Address.CountryCode, }, } } // Organizations organizations := make([]tender.Organization, len(n.Organizations)) for i, org := range n.Organizations { organizations[i] = tender.Organization{ Name: org.Name, CompanyID: org.CompanyID, WebsiteURI: org.WebsiteURI, ContactName: org.ContactName, ContactTelephone: org.ContactTelephone, ContactEmail: org.ContactEmail, ContactFax: org.ContactFax, Role: org.Role, Address: tender.Address{ StreetName: org.Address.StreetName, CityName: org.Address.CityName, PostalZone: org.Address.PostalZone, CountrySubentityCode: org.Address.CountrySubentityCode, Department: org.Address.Department, Region: org.Address.Region, CountryCode: org.Address.CountryCode, }, } } // Selection Criteria selectionCriteria := make([]tender.SelectionCriterion, len(n.SelectionCriteria)) for i, criterion := range n.SelectionCriteria { selectionCriteria[i] = tender.SelectionCriterion{ TypeCode: criterion.TypeCode, Description: criterion.Description, LanguageID: criterion.LanguageID, } } // Winning Tenderer winningTenderer := &tender.Organization{} if n.WinningTenderer != nil { winningTenderer = &tender.Organization{ Name: n.WinningTenderer.Name, CompanyID: n.WinningTenderer.CompanyID, WebsiteURI: n.WinningTenderer.WebsiteURI, ContactName: n.WinningTenderer.ContactName, ContactTelephone: n.WinningTenderer.ContactTelephone, ContactEmail: n.WinningTenderer.ContactEmail, ContactFax: n.WinningTenderer.ContactFax, Role: n.WinningTenderer.Role, Address: tender.Address{ StreetName: n.WinningTenderer.Address.StreetName, CityName: n.WinningTenderer.Address.CityName, PostalZone: n.WinningTenderer.Address.PostalZone, CountrySubentityCode: n.WinningTenderer.Address.CountrySubentityCode, Department: n.WinningTenderer.Address.Department, Region: n.WinningTenderer.Address.Region, CountryCode: n.WinningTenderer.Address.CountryCode, }, } } // Modifications modifications := make([]tender.TenderModification, len(n.Modifications)) for i, modification := range n.Modifications { modifications[i] = tender.TenderModification{ ModificationDate: modification.ModificationDate, ModificationReason: modification.ModificationReason, Description: modification.Description, LanguageID: modification.LanguageID, } } // Awarded Entities awardedEntities := make([]tender.Awarded, len(n.AwardedEntities)) for i, awarded := range n.AwardedEntities { awardedEntities[i] = tender.Awarded{ Name: awarded.Name, Address: awarded.Address, Country: awarded.Country, Amount: awarded.Amount, Currency: awarded.Currency, Share: awarded.Share, AwardDate: awarded.AwardDate, ContractID: awarded.ContractID, TenderID: awarded.TenderID, LotID: awarded.LotID, CompanyID: awarded.CompanyID, OrganizationID: awarded.OrganizationID, } } t.NoticePublicationID = n.NoticePublicationID t.Title = n.Title t.Description = n.Description t.ProcurementTypeCode = n.ProcurementTypeCode t.ProcedureCode = n.ProcedureCode t.EstimatedValue = n.EstimatedValue t.Currency = n.Currency t.TenderDeadline = n.TenderDeadline t.SubmissionURL = n.SubmissionURL t.BuyerOrganization = buyerOrg t.ReviewOrganization = reviewOrg t.Organizations = organizations t.SelectionCriteria = selectionCriteria t.WinningTenderer = winningTenderer t.Modifications = modifications t.AwardedEntities = awardedEntities t.NoticeTypeCode = n.NoticeTypeCode t.NoticeSubTypeCode = n.NoticeSubTypeCode t.NoticeLanguageCode = n.NoticeLanguageCode t.IssueDate = n.IssueDate t.IssueTime = n.IssueTime t.PublicationDate = n.PublicationDate t.SubmissionDeadline = n.SubmissionDeadline t.ApplicationDeadline = n.ApplicationDeadline t.GazetteID = n.GazetteID t.PlaceOfPerformance = n.PlaceOfPerformance t.CountryCode = n.CountryCode t.RegionCode = n.RegionCode t.CityName = n.CityName t.PostalCode = n.PostalCode t.DocumentURI = n.DocumentURI t.TenderURL = n.TenderURL t.MainClassification = n.MainClassification t.AdditionalClassifications = n.AdditionalClassifications t.OfficialLanguages = n.OfficialLanguages t.CancellationReason = n.CancellationReason t.CancellationDate = n.CancellationDate t.AwardDate = n.AwardDate t.AwardedValue = n.AwardedValue t.ContractNumber = n.ContractNumber t.SuspensionReason = n.SuspensionReason t.SuspensionDate = n.SuspensionDate t.WinningTenderer = winningTenderer t.Modifications = modifications t.AwardedEntities = awardedEntities return nil }