package contract import ( "encoding/xml" "time" "tm/internal/tender" "tm/ted/eform" ) // Notice represents the UBL ContractNotice structure used by TED type ContractNotice struct { XMLName xml.Name `xml:"ContractNotice"` UBLVersionID string `xml:"UBLVersionID"` CustomizationID string `xml:"CustomizationID"` ID string `xml:"ID"` ContractFolderID string `xml:"ContractFolderID"` IssueDate string `xml:"IssueDate"` IssueTime string `xml:"IssueTime"` VersionID string `xml:"VersionID"` RegulatoryDomain string `xml:"RegulatoryDomain"` NoticeTypeCode string `xml:"NoticeTypeCode"` NoticeLanguageCode string `xml:"NoticeLanguageCode"` UBLExtensions eform.UBLExtensions `xml:"UBLExtensions,omitempty"` ContractingParty eform.ContractingParty `xml:"ContractingParty"` TenderingTerms eform.TenderingTerms `xml:"TenderingTerms,omitempty"` TenderingProcess eform.TenderingProcess `xml:"TenderingProcess,omitempty"` ProcurementProject eform.ProcurementProject `xml:"ProcurementProject"` ProcurementProjectLot []eform.ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"` } func (notice ContractNotice) MapToTender() *tender.Tender { now := time.Now().Unix() t := &tender.Tender{ ContractNoticeID: notice.ID, ContractFolderID: notice.ContractFolderID, NoticeTypeCode: notice.NoticeTypeCode, // NoticeSubTypeCode: notice.NoticeSubTypeCode, NoticeLanguageCode: notice.NoticeLanguageCode, // IssueDate: parseDateToUnixMilli(notice.IssueDate), // IssueTime: parseTimeToUnixMilli(notice.IssueTime), // GazetteID: notice.GetOJSID(), // Title: notice.GetProcurementTitle(), // Description: notice.GetProcurementDescription(), // ProcurementTypeCode: notice.GetContractNature(), // ProcedureCode: notice.GetProcedureCode(), // MainClassification: notice.GetMainClassification(), // PlaceOfPerformance: notice.GetPlaceOfPerformance(), // DocumentURI: notice.GetDocumentURI(), Status: tender.TenderStatusActive, Source: tender.TenderSourceTEDScraper, ProcessingMetadata: tender.ProcessingMetadata{ ScrapedAt: now, ProcessedAt: now, ProcessingVersion: "1.0", }, } // Set publication information // if pubInfo := notice.GetPublicationInfo(); pubInfo != nil { // t.NoticePublicationID = pubInfo.NoticePublicationID // t.PublicationDate = s.parseDateToUnixMilli(pubInfo.PublicationDate) // t.TenderURL = s.generateTenderURL(pubInfo.NoticePublicationID) // } // Set additional classifications // if notice.ProcurementProject != nil && notice.ProcurementProject.AdditionalCommodityClassification != nil { // for _, additionalClass := range notice.ProcurementProject.AdditionalCommodityClassification { // if additionalClass.ItemClassificationCode != "" { // t.AdditionalClassifications = append(t.AdditionalClassifications, additionalClass.ItemClassificationCode) // } // } // } // Set estimated value and currency // if amount, currency := notice.GetBudget(); amount != "" { // if value, err := strconv.ParseFloat(amount, 64); err == nil { // t.EstimatedValue = value // t.Currency = currency // } // } // Set duration information // if duration, unit := notice.GetDuration(); duration != "" { // t.Duration = duration // t.DurationUnit = unit // } // Set tender deadline // if deadline := notice.GetTenderDeadline(); deadline != "" { // t.TenderDeadline = parseDateToUnixMilli(deadline) // if deadlineTime, err := parseDate(deadline); err == nil { // applicationDeadline := calculateApplicationDeadline(deadlineTime) // t.ApplicationDeadline = applicationDeadline.UnixMilli() // } // } // if pubDate, err := parseDate(notice.GetPublicationDate()); err == nil { // submissionDeadline := calculateSubmissionDeadline(pubDate) // t.SubmissionDeadline = submissionDeadline.UnixMilli() // } // Set SubmissionURL from TenderingTerms // if notice.ProcurementProjectLot != nil && notice.ProcurementProjectLot.TenderingTerms != nil { // if tenderingTerms := notice.ProcurementProjectLot.TenderingTerms; tenderingTerms.TenderRecipientParty != nil { // if endpointID := tenderingTerms.TenderRecipientParty.EndpointID; endpointID != "" { // if strings.HasPrefix(endpointID, "http") { // t.SubmissionURL = endpointID // } else { // t.SubmissionURL = "https://" + endpointID // } // } // } // } // Set location information // if notice.ProcurementProject != nil && notice.ProcurementProject.RealizedLocation != nil { // if addr := notice.ProcurementProject.RealizedLocation.Address; addr != nil { // t.CityName = addr.CityName // t.PostalCode = addr.PostalZone // t.RegionCode = addr.CountrySubentityCode // if addr.Country != nil { // t.CountryCode = addr.Country.IdentificationCode // } // } // } // Set buyer organization // buyerID := notice.GetBuyerID() // if buyerID != "" { // if buyerOrg := notice.GetOrganizationByID(buyerID); buyerOrg != nil { // t.BuyerOrganization = s.mapOrganization(buyerOrg, "buyer") // } // } // Set review organization // reviewID := notice.GetReviewOrganizationID() // if reviewID != "" { // if reviewOrg := notice.GetOrganizationByID(reviewID); reviewOrg != nil { // t.ReviewOrganization = s.mapOrganization(reviewOrg, "review") // } // } // Set all organizations // if orgs := notice.GetOrganizations(); orgs != nil { // for _, org := range orgs.Organization { // mappedOrg := s.mapOrganization(&org, "") // if mappedOrg != nil { // t.Organizations = append(t.Organizations, *mappedOrg) // } // } // } // Set selection criteria // if criteria := notice.GetSelectionCriteria(); criteria != nil { // for _, criterion := range criteria { // t.SelectionCriteria = append(t.SelectionCriteria, tender.SelectionCriterion{ // TypeCode: criterion.CriterionTypeCode, // Description: criterion.Description, // LanguageID: criterion.LanguageID, // }) // } // } // Set official languages // if languages := notice.GetOfficialLanguages(); languages != nil { // t.OfficialLanguages = languages // } // Generate unique tender ID // t.TenderID = generateTenderID(t) return t } // GetID returns the contract notice ID func (cn ContractNotice) GetID() string { return cn.ID } // Validate validates the parsed model func (cn ContractNotice) Validate() error { return nil } // GetMainBuyer returns the lead/main buyer organization func (n *ContractNotice) GetMainBuyer() *eform.Organization { if len(n.UBLExtensions.UBLExtension) > 0 { orgs := n.UBLExtensions.UBLExtension[0].ExtensionContent.EformsExtension.Organizations.Organization for i := range orgs { for _, role := range orgs[i].Roles { if role == eform.RoleBuyer || role == eform.RoleLeadBuyer { return &orgs[i] } } } } return nil } // GetOrganizationByID retrieves organization by ID func (n *ContractNotice) GetOrganizationByID(id string) *eform.Organization { if len(n.UBLExtensions.UBLExtension) > 0 { orgs := n.UBLExtensions.UBLExtension[0].ExtensionContent.EformsExtension.Organizations.Organization for i := range orgs { if orgs[i].ID == id { return &orgs[i] } } } return nil }