added missing tender data to response
This commit is contained in:
+224
-73
@@ -19,7 +19,9 @@ func mapProcurementLotFromTED(lot *ProcurementProjectLot) notice.ProcurementLot
|
||||
out.Description = pp.Description
|
||||
out.MainNatureOfContract = pp.ProcurementTypeCode
|
||||
if pp.MainCommodityClassification != nil {
|
||||
out.MainClassification = strings.TrimSpace(pp.MainCommodityClassification.ItemClassificationCode)
|
||||
mc := pp.MainCommodityClassification
|
||||
out.MainClassification = strings.TrimSpace(mc.ItemClassificationCode)
|
||||
out.MainClassificationDescription = mainCommodityClassificationLabel(mc)
|
||||
}
|
||||
for _, ac := range pp.AdditionalCommodityClassification {
|
||||
c := strings.TrimSpace(ac.ItemClassificationCode)
|
||||
@@ -86,7 +88,7 @@ func (s *TEDScraper) mapToTenderFromParsedDoc(parsedDoc *ParsedDocument, sourceF
|
||||
})
|
||||
return nil
|
||||
}
|
||||
return s.mapGenericNoticeToTender(parsedDoc.PriorInformationNotice, sourceFileURL, sourceFileName)
|
||||
return s.mapPriorInformationNoticeToTender(parsedDoc.PriorInformationNotice, sourceFileURL, sourceFileName)
|
||||
default:
|
||||
s.logger.Error("Unknown document type for mapping", map[string]interface{}{
|
||||
"document_type": string(parsedDoc.Type),
|
||||
@@ -95,34 +97,41 @@ func (s *TEDScraper) mapToTenderFromParsedDoc(parsedDoc *ParsedDocument, sourceF
|
||||
}
|
||||
}
|
||||
|
||||
// mapGenericNoticeToTender maps any TED document type to tender entity using the common interface
|
||||
func (s *TEDScraper) mapGenericNoticeToTender(doc TEDDocument, sourceFileURL, sourceFileName string) *notice.Notice {
|
||||
if doc == nil {
|
||||
s.logger.Error("Document is nil in mapGenericNoticeToTender", map[string]interface{}{})
|
||||
// mapPriorInformationNoticeToTender maps a TED PriorInformationNotice to the same notice shape as a contract notice,
|
||||
// so procedure keys (ContractFolderID, NoticePublicationID, ProcurementProjectID) merge into one tender.
|
||||
func (s *TEDScraper) mapPriorInformationNoticeToTender(pin *PriorInformationNotice, sourceFileURL, sourceFileName string) *notice.Notice {
|
||||
if pin == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
t := ¬ice.Notice{
|
||||
ContractNoticeID: doc.GetID(),
|
||||
ContractFolderID: "", // Not available in generic interface
|
||||
NoticeTypeCode: doc.GetNoticeType(),
|
||||
NoticeSubTypeCode: "", // Not available in generic interface
|
||||
NoticeLanguageCode: doc.GetLanguage(),
|
||||
IssueDate: now, // TODO: Parse actual date from document
|
||||
IssueTime: now, // TODO: Parse actual time from document
|
||||
GazetteID: "", // Not available in generic interface
|
||||
NoticePublicationID: "", // Not available in generic interface
|
||||
PublicationDate: now, // TODO: Parse actual publication date
|
||||
|
||||
// Basic tender information
|
||||
Title: "Generic Notice " + doc.GetNoticeType(),
|
||||
Description: "Processed from " + doc.GetNoticeType() + " document",
|
||||
Status: notice.TenderStatusActive,
|
||||
Source: notice.TenderSourceTEDScraper,
|
||||
SourceFileURL: sourceFileURL,
|
||||
SourceFileName: sourceFileName,
|
||||
ContractNoticeID: pin.ID,
|
||||
ContractFolderID: pin.ContractFolderID,
|
||||
ProcurementProjectID: procurementProjectIDFromPriorInformationNotice(pin),
|
||||
NoticeTypeCode: strings.TrimSpace(pin.GetNoticeType()),
|
||||
FormType: pin.GetNoticeFormType(),
|
||||
NoticeSubTypeCode: pin.GetNoticeSubType(),
|
||||
NoticeIdentifier: pin.ID,
|
||||
NoticeVersion: pin.VersionID,
|
||||
NoticeDispatchAt: ParseIssueDateTimeToUnix(pin.IssueDate, pin.IssueTime),
|
||||
ESenderDispatchAt: TransmissionDispatchUnix(pin.Extensions),
|
||||
NoticeLanguageCode: pin.NoticeLanguageCode,
|
||||
IssueDate: ParseDateToUnix(pin.IssueDate),
|
||||
IssueTime: ParseTimeToUnix(pin.IssueTime),
|
||||
GazetteID: pin.GetOJSID(),
|
||||
Title: pin.GetProcurementTitle(),
|
||||
Description: pin.GetProcurementDescription(),
|
||||
ProcurementTypeCode: pin.GetContractNature(),
|
||||
ProcedureCode: pin.GetProcedureCode(),
|
||||
MainClassification: pin.GetMainClassification(),
|
||||
MainClassificationDescription: pin.GetMainClassificationDescription(),
|
||||
PlaceOfPerformance: pin.GetPlaceOfPerformance(),
|
||||
DocumentURI: pin.GetDocumentURI(),
|
||||
Status: notice.TenderStatusActive,
|
||||
Source: notice.TenderSourceTEDScraper,
|
||||
SourceFileURL: sourceFileURL,
|
||||
SourceFileName: sourceFileName,
|
||||
ProcessingMetadata: notice.ProcessingMetadata{
|
||||
ScrapedAt: now,
|
||||
ProcessedAt: now,
|
||||
@@ -130,39 +139,180 @@ func (s *TEDScraper) mapGenericNoticeToTender(doc TEDDocument, sourceFileURL, so
|
||||
},
|
||||
}
|
||||
|
||||
if pubInfo := pin.GetPublicationInfo(); pubInfo != nil {
|
||||
t.NoticePublicationID = pubInfo.NoticePublicationID
|
||||
t.PublicationDate = ParseDateToUnix(pubInfo.PublicationDate)
|
||||
t.TenderURL = GenerateTenderURL(pubInfo.NoticePublicationID)
|
||||
}
|
||||
|
||||
if pin.ProcurementProject != nil && pin.ProcurementProject.AdditionalCommodityClassification != nil {
|
||||
for _, additionalClass := range pin.ProcurementProject.AdditionalCommodityClassification {
|
||||
if additionalClass.ItemClassificationCode != "" {
|
||||
t.AdditionalClassifications = append(t.AdditionalClassifications, additionalClass.ItemClassificationCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if amount, currency := pin.GetBudget(); amount != "" {
|
||||
if value, ok := ParseEuropeanAmount(amount); ok {
|
||||
t.EstimatedValue = value
|
||||
t.Currency = currency
|
||||
}
|
||||
}
|
||||
|
||||
if pin.ContractingParty != nil {
|
||||
t.BuyerProfileURL = pin.ContractingParty.BuyerProfileURI
|
||||
}
|
||||
|
||||
for i := range pin.ProcurementProjectLot {
|
||||
t.ProcurementLots = append(t.ProcurementLots, mapProcurementLotFromTED(&pin.ProcurementProjectLot[i]))
|
||||
}
|
||||
|
||||
if duration, unit := pin.GetDuration(); duration != "" {
|
||||
t.Duration = duration
|
||||
t.DurationUnit = unit
|
||||
}
|
||||
|
||||
if deadline := pin.GetTenderDeadline(); deadline != "" {
|
||||
t.TenderDeadline = ParseDateToUnix(deadline)
|
||||
if deadlineTime, err := ParseDate(deadline); err == nil {
|
||||
applicationDeadline := CalculateApplicationDeadline(deadlineTime)
|
||||
t.ApplicationDeadline = applicationDeadline.Unix()
|
||||
}
|
||||
}
|
||||
|
||||
if pubDate, err := ParseDate(pin.GetPublicationDate()); err == nil {
|
||||
submissionDeadline := CalculateSubmissionDeadline(pubDate)
|
||||
t.SubmissionDeadline = submissionDeadline.Unix()
|
||||
}
|
||||
|
||||
if lot := pin.firstLot(); lot != nil && lot.TenderingTerms != nil {
|
||||
if tenderingTerms := lot.TenderingTerms; tenderingTerms.TenderRecipientParty != nil {
|
||||
if endpointID := tenderingTerms.TenderRecipientParty.EndpointID; endpointID != "" {
|
||||
if strings.HasPrefix(endpointID, "http") {
|
||||
t.SubmissionURL = endpointID
|
||||
} else {
|
||||
t.SubmissionURL = "https://" + endpointID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pin.ProcurementProject != nil && pin.ProcurementProject.RealizedLocation != nil {
|
||||
if addr := pin.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
|
||||
}
|
||||
}
|
||||
} else if lot := pin.firstLot(); lot != nil && lot.ProcurementProject != nil &&
|
||||
lot.ProcurementProject.RealizedLocation != nil {
|
||||
if addr := lot.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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buyerID := pin.GetBuyerID()
|
||||
if buyerID != "" {
|
||||
if buyerOrg := pin.GetOrganizationByID(buyerID); buyerOrg != nil {
|
||||
t.BuyerOrganization = s.mapOrganization(buyerOrg, "buyer")
|
||||
}
|
||||
}
|
||||
|
||||
reviewID := pin.GetReviewOrganizationID()
|
||||
if reviewID != "" {
|
||||
if reviewOrg := pin.GetOrganizationByID(reviewID); reviewOrg != nil {
|
||||
t.ReviewOrganization = s.mapOrganization(reviewOrg, "review")
|
||||
}
|
||||
}
|
||||
|
||||
if orgs := pin.GetOrganizations(); orgs != nil {
|
||||
for _, org := range orgs.Organization {
|
||||
mappedOrg := s.mapOrganization(&org, "")
|
||||
if mappedOrg != nil {
|
||||
t.Organizations = append(t.Organizations, *mappedOrg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if criteria := pin.GetSelectionCriteria(); criteria != nil {
|
||||
for _, criterion := range criteria {
|
||||
t.SelectionCriteria = append(t.SelectionCriteria, notice.SelectionCriterion{
|
||||
TypeCode: criterion.CriterionTypeCode,
|
||||
Description: criterion.Description,
|
||||
LanguageID: criterion.LanguageID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if languages := pin.GetOfficialLanguages(); languages != nil {
|
||||
t.OfficialLanguages = languages
|
||||
}
|
||||
|
||||
if strings.TrimSpace(t.Title) == "" {
|
||||
if np := strings.TrimSpace(t.NoticePublicationID); np != "" {
|
||||
t.Title = "Prior information notice " + np
|
||||
} else if cf := strings.TrimSpace(t.ContractFolderID); cf != "" {
|
||||
t.Title = "Prior information notice — procedure " + cf
|
||||
}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func procurementProjectIDFromPriorInformationNotice(pin *PriorInformationNotice) string {
|
||||
if pin == nil {
|
||||
return ""
|
||||
}
|
||||
if pin.ProcurementProject != nil {
|
||||
if id := strings.TrimSpace(pin.ProcurementProject.ID); id != "" {
|
||||
return id
|
||||
}
|
||||
}
|
||||
if lot := pin.firstLot(); lot != nil && lot.ProcurementProject != nil {
|
||||
return strings.TrimSpace(lot.ProcurementProject.ID)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// mapToTender maps a TED ContractNotice to tender entity
|
||||
func (s *TEDScraper) mapToTender(cn *ContractNotice, sourceFileURL, sourceFileName string) *notice.Notice {
|
||||
now := time.Now().Unix()
|
||||
|
||||
t := ¬ice.Notice{
|
||||
ContractNoticeID: cn.ID,
|
||||
ContractFolderID: cn.ContractFolderID,
|
||||
ProcurementProjectID: procurementProjectIDFromContractNotice(cn),
|
||||
NoticeTypeCode: strings.TrimSpace(cn.GetNoticeType()),
|
||||
FormType: cn.GetNoticeFormType(),
|
||||
NoticeSubTypeCode: cn.GetNoticeSubType(),
|
||||
NoticeIdentifier: cn.ID,
|
||||
NoticeVersion: cn.VersionID,
|
||||
NoticeDispatchAt: ParseIssueDateTimeToUnix(cn.IssueDate, cn.IssueTime),
|
||||
ESenderDispatchAt: TransmissionDispatchUnix(cn.Extensions),
|
||||
NoticeLanguageCode: cn.NoticeLanguageCode,
|
||||
IssueDate: ParseDateToUnix(cn.IssueDate),
|
||||
IssueTime: ParseTimeToUnix(cn.IssueTime),
|
||||
GazetteID: cn.GetOJSID(),
|
||||
Title: cn.GetProcurementTitle(),
|
||||
Description: cn.GetProcurementDescription(),
|
||||
ProcurementTypeCode: cn.GetContractNature(),
|
||||
ProcedureCode: cn.GetProcedureCode(),
|
||||
MainClassification: cn.GetMainClassification(),
|
||||
PlaceOfPerformance: cn.GetPlaceOfPerformance(),
|
||||
DocumentURI: cn.GetDocumentURI(),
|
||||
Status: notice.TenderStatusActive,
|
||||
Source: notice.TenderSourceTEDScraper,
|
||||
SourceFileURL: sourceFileURL,
|
||||
SourceFileName: sourceFileName,
|
||||
ContractNoticeID: cn.ID,
|
||||
ContractFolderID: cn.ContractFolderID,
|
||||
ProcurementProjectID: procurementProjectIDFromContractNotice(cn),
|
||||
NoticeTypeCode: strings.TrimSpace(cn.GetNoticeType()),
|
||||
FormType: cn.GetNoticeFormType(),
|
||||
NoticeSubTypeCode: cn.GetNoticeSubType(),
|
||||
NoticeIdentifier: cn.ID,
|
||||
NoticeVersion: cn.VersionID,
|
||||
NoticeDispatchAt: ParseIssueDateTimeToUnix(cn.IssueDate, cn.IssueTime),
|
||||
ESenderDispatchAt: TransmissionDispatchUnix(cn.Extensions),
|
||||
NoticeLanguageCode: cn.NoticeLanguageCode,
|
||||
IssueDate: ParseDateToUnix(cn.IssueDate),
|
||||
IssueTime: ParseTimeToUnix(cn.IssueTime),
|
||||
GazetteID: cn.GetOJSID(),
|
||||
Title: cn.GetProcurementTitle(),
|
||||
Description: cn.GetProcurementDescription(),
|
||||
ProcurementTypeCode: cn.GetContractNature(),
|
||||
ProcedureCode: cn.GetProcedureCode(),
|
||||
MainClassification: cn.GetMainClassification(),
|
||||
MainClassificationDescription: cn.GetMainClassificationDescription(),
|
||||
PlaceOfPerformance: cn.GetPlaceOfPerformance(),
|
||||
DocumentURI: cn.GetDocumentURI(),
|
||||
Status: notice.TenderStatusActive,
|
||||
Source: notice.TenderSourceTEDScraper,
|
||||
SourceFileURL: sourceFileURL,
|
||||
SourceFileName: sourceFileName,
|
||||
ProcessingMetadata: notice.ProcessingMetadata{
|
||||
ScrapedAt: now,
|
||||
ProcessedAt: now,
|
||||
@@ -298,29 +448,30 @@ func (s *TEDScraper) mapContractAwardNoticeToTender(can *ContractAwardNotice, so
|
||||
now := time.Now().Unix()
|
||||
|
||||
t := ¬ice.Notice{
|
||||
ContractNoticeID: can.ID,
|
||||
ContractFolderID: can.ContractFolderID,
|
||||
ProcurementProjectID: procurementProjectIDFromContractAwardNotice(can),
|
||||
NoticeTypeCode: strings.TrimSpace(can.GetNoticeType()),
|
||||
FormType: can.GetNoticeFormType(),
|
||||
NoticeSubTypeCode: can.GetNoticeSubType(),
|
||||
NoticeIdentifier: can.ID,
|
||||
NoticeVersion: can.VersionID,
|
||||
NoticeDispatchAt: ParseIssueDateTimeToUnix(can.IssueDate, can.IssueTime),
|
||||
ESenderDispatchAt: TransmissionDispatchUnix(can.Extensions),
|
||||
NoticeLanguageCode: can.NoticeLanguageCode,
|
||||
IssueDate: ParseDateToUnix(can.IssueDate),
|
||||
IssueTime: ParseTimeToUnix(can.IssueTime),
|
||||
GazetteID: can.GetOJSID(),
|
||||
Title: can.GetProcurementTitle(),
|
||||
Description: can.GetProcurementDescription(),
|
||||
ProcurementTypeCode: can.GetContractNature(),
|
||||
ProcedureCode: can.GetProcedureCode(),
|
||||
MainClassification: can.GetMainClassification(),
|
||||
Status: notice.TenderStatusAwarded, // Award notices are for completed tenders
|
||||
Source: notice.TenderSourceTEDScraper,
|
||||
SourceFileURL: sourceFileURL,
|
||||
SourceFileName: sourceFileName,
|
||||
ContractNoticeID: can.ID,
|
||||
ContractFolderID: can.ContractFolderID,
|
||||
ProcurementProjectID: procurementProjectIDFromContractAwardNotice(can),
|
||||
NoticeTypeCode: strings.TrimSpace(can.GetNoticeType()),
|
||||
FormType: can.GetNoticeFormType(),
|
||||
NoticeSubTypeCode: can.GetNoticeSubType(),
|
||||
NoticeIdentifier: can.ID,
|
||||
NoticeVersion: can.VersionID,
|
||||
NoticeDispatchAt: ParseIssueDateTimeToUnix(can.IssueDate, can.IssueTime),
|
||||
ESenderDispatchAt: TransmissionDispatchUnix(can.Extensions),
|
||||
NoticeLanguageCode: can.NoticeLanguageCode,
|
||||
IssueDate: ParseDateToUnix(can.IssueDate),
|
||||
IssueTime: ParseTimeToUnix(can.IssueTime),
|
||||
GazetteID: can.GetOJSID(),
|
||||
Title: can.GetProcurementTitle(),
|
||||
Description: can.GetProcurementDescription(),
|
||||
ProcurementTypeCode: can.GetContractNature(),
|
||||
ProcedureCode: can.GetProcedureCode(),
|
||||
MainClassification: can.GetMainClassification(),
|
||||
MainClassificationDescription: can.GetMainClassificationDescription(),
|
||||
Status: notice.TenderStatusAwarded, // Award notices are for completed tenders
|
||||
Source: notice.TenderSourceTEDScraper,
|
||||
SourceFileURL: sourceFileURL,
|
||||
SourceFileName: sourceFileName,
|
||||
ProcessingMetadata: notice.ProcessingMetadata{
|
||||
ScrapedAt: now,
|
||||
ProcessedAt: now,
|
||||
|
||||
+321
-23
@@ -55,6 +55,14 @@ type TEDDocument interface {
|
||||
Validate() error
|
||||
}
|
||||
|
||||
// ublEformsExtension returns embedded eForms extension data from UBL extensions (shared across notice root types).
|
||||
func ublEformsExtension(ext *UBLExtensions) *EformsExtension {
|
||||
if ext == nil || ext.UBLExtension == nil || ext.UBLExtension.ExtensionContent == nil {
|
||||
return nil
|
||||
}
|
||||
return ext.UBLExtension.ExtensionContent.EformsExtension
|
||||
}
|
||||
|
||||
// PriorInformationNotice represents a prior information notice
|
||||
type PriorInformationNotice struct {
|
||||
XMLName xml.Name `xml:"PriorInformationNotice"`
|
||||
@@ -73,7 +81,7 @@ type PriorInformationNotice struct {
|
||||
IssueTime string `xml:"IssueTime"`
|
||||
VersionID string `xml:"VersionID"`
|
||||
RegulatoryDomain string `xml:"RegulatoryDomain"`
|
||||
NoticeTypeCode string `xml:"NoticeTypeCode"`
|
||||
NoticeTypeCode NoticeTypeCodeField `xml:"NoticeTypeCode,omitempty"`
|
||||
NoticeLanguageCode string `xml:"NoticeLanguageCode"`
|
||||
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
||||
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
||||
@@ -90,7 +98,274 @@ func (pin PriorInformationNotice) GetID() string {
|
||||
}
|
||||
|
||||
func (pin PriorInformationNotice) GetNoticeType() string {
|
||||
return pin.NoticeTypeCode
|
||||
return strings.TrimSpace(pin.NoticeTypeCode.Text)
|
||||
}
|
||||
|
||||
// GetNoticeFormType returns the form type from listName on cbc:NoticeTypeCode (BT-03), e.g. "planning".
|
||||
func (pin PriorInformationNotice) GetNoticeFormType() string {
|
||||
return strings.TrimSpace(pin.NoticeTypeCode.ListName)
|
||||
}
|
||||
|
||||
func (pin PriorInformationNotice) firstLot() *ProcurementProjectLot {
|
||||
if len(pin.ProcurementProjectLot) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &pin.ProcurementProjectLot[0]
|
||||
}
|
||||
|
||||
// GetPublicationInfo returns publication information if available.
|
||||
func (pin PriorInformationNotice) GetPublicationInfo() *Publication {
|
||||
if ef := ublEformsExtension(pin.Extensions); ef != nil {
|
||||
return ef.Publication
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOrganizations returns organizations from extensions.
|
||||
func (pin PriorInformationNotice) GetOrganizations() *Organizations {
|
||||
if ef := ublEformsExtension(pin.Extensions); ef != nil {
|
||||
return ef.Organizations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNoticeSubType returns the notice subtype code from extensions.
|
||||
func (pin PriorInformationNotice) GetNoticeSubType() string {
|
||||
if ef := ublEformsExtension(pin.Extensions); ef != nil && ef.NoticeSubType != nil {
|
||||
return ef.NoticeSubType.SubTypeCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetNoticePublicationID returns the notice publication ID from extensions.
|
||||
func (pin PriorInformationNotice) GetNoticePublicationID() string {
|
||||
pub := pin.GetPublicationInfo()
|
||||
if pub != nil {
|
||||
return pub.NoticePublicationID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetOJSID returns the OJS gazette ID from extensions.
|
||||
func (pin PriorInformationNotice) GetOJSID() string {
|
||||
pub := pin.GetPublicationInfo()
|
||||
if pub != nil {
|
||||
return pub.GazetteID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetPublicationDate returns the publication date from extensions.
|
||||
func (pin PriorInformationNotice) GetPublicationDate() string {
|
||||
pub := pin.GetPublicationInfo()
|
||||
if pub != nil {
|
||||
return pub.PublicationDate
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetOrganizationByID returns an organization by its ID.
|
||||
func (pin PriorInformationNotice) GetOrganizationByID(orgID string) *Organization {
|
||||
orgs := pin.GetOrganizations()
|
||||
if orgs == nil {
|
||||
return nil
|
||||
}
|
||||
for _, org := range orgs.Organization {
|
||||
if org.Company != nil &&
|
||||
org.Company.PartyIdentification != nil &&
|
||||
org.Company.PartyIdentification.ID == orgID {
|
||||
return &org
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBuyerID returns the buyer organization ID from contracting party.
|
||||
func (pin PriorInformationNotice) GetBuyerID() string {
|
||||
if pin.ContractingParty != nil &&
|
||||
pin.ContractingParty.Party != nil &&
|
||||
pin.ContractingParty.Party.PartyIdentification != nil {
|
||||
return pin.ContractingParty.Party.PartyIdentification.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetReviewOrganizationID returns the review organization ID from appeal terms.
|
||||
func (pin PriorInformationNotice) GetReviewOrganizationID() string {
|
||||
if pin.firstLot() != nil &&
|
||||
pin.firstLot().TenderingTerms != nil &&
|
||||
pin.firstLot().TenderingTerms.AppealTerms != nil &&
|
||||
pin.firstLot().TenderingTerms.AppealTerms.AppealReceiverParty != nil &&
|
||||
pin.firstLot().TenderingTerms.AppealTerms.AppealReceiverParty.PartyIdentification != nil {
|
||||
return pin.firstLot().TenderingTerms.AppealTerms.AppealReceiverParty.PartyIdentification.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetProcedureCode returns the type of procedure.
|
||||
func (pin PriorInformationNotice) GetProcedureCode() string {
|
||||
if pin.TenderingProcess != nil {
|
||||
return pin.TenderingProcess.ProcedureCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetProcurementTitle returns the procurement project title.
|
||||
func (pin PriorInformationNotice) GetProcurementTitle() string {
|
||||
if pin.ProcurementProject != nil && strings.TrimSpace(pin.ProcurementProject.Name) != "" {
|
||||
return pin.ProcurementProject.Name
|
||||
}
|
||||
if pin.firstLot() != nil && pin.firstLot().ProcurementProject != nil {
|
||||
return pin.firstLot().ProcurementProject.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetProcurementDescription returns the procurement project description.
|
||||
func (pin PriorInformationNotice) GetProcurementDescription() string {
|
||||
if pin.ProcurementProject != nil && strings.TrimSpace(pin.ProcurementProject.Description) != "" {
|
||||
return pin.ProcurementProject.Description
|
||||
}
|
||||
if pin.firstLot() != nil && pin.firstLot().ProcurementProject != nil {
|
||||
return pin.firstLot().ProcurementProject.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetContractNature returns the main nature of the contract.
|
||||
func (pin PriorInformationNotice) GetContractNature() string {
|
||||
if pin.ProcurementProject != nil && strings.TrimSpace(pin.ProcurementProject.ProcurementTypeCode) != "" {
|
||||
return pin.ProcurementProject.ProcurementTypeCode
|
||||
}
|
||||
if pin.firstLot() != nil && pin.firstLot().ProcurementProject != nil {
|
||||
return pin.firstLot().ProcurementProject.ProcurementTypeCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetMainClassification returns the main CPV classification code.
|
||||
func (pin PriorInformationNotice) GetMainClassification() string {
|
||||
if pin.ProcurementProject != nil &&
|
||||
pin.ProcurementProject.MainCommodityClassification != nil {
|
||||
return pin.ProcurementProject.MainCommodityClassification.ItemClassificationCode
|
||||
}
|
||||
if lot := pin.firstLot(); lot != nil && lot.ProcurementProject != nil &&
|
||||
lot.ProcurementProject.MainCommodityClassification != nil {
|
||||
return lot.ProcurementProject.MainCommodityClassification.ItemClassificationCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetMainClassificationDescription returns the CPV / item classification description when present in the notice XML.
|
||||
func (pin PriorInformationNotice) GetMainClassificationDescription() string {
|
||||
if pin.ProcurementProject != nil {
|
||||
if s := mainCommodityClassificationLabel(pin.ProcurementProject.MainCommodityClassification); s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
if lot := pin.firstLot(); lot != nil && lot.ProcurementProject != nil {
|
||||
return mainCommodityClassificationLabel(lot.ProcurementProject.MainCommodityClassification)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetPlaceOfPerformance returns the place of performance.
|
||||
func (pin PriorInformationNotice) GetPlaceOfPerformance() string {
|
||||
if pin.ProcurementProject != nil &&
|
||||
pin.ProcurementProject.RealizedLocation != nil &&
|
||||
pin.ProcurementProject.RealizedLocation.Address != nil {
|
||||
return pin.ProcurementProject.RealizedLocation.Address.Region
|
||||
}
|
||||
if lot := pin.firstLot(); lot != nil && lot.ProcurementProject != nil &&
|
||||
lot.ProcurementProject.RealizedLocation != nil &&
|
||||
lot.ProcurementProject.RealizedLocation.Address != nil {
|
||||
return lot.ProcurementProject.RealizedLocation.Address.Region
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetSelectionCriteria returns selection criteria from extensions.
|
||||
func (pin PriorInformationNotice) GetSelectionCriteria() []SelectionCriteria {
|
||||
if ef := ublEformsExtension(pin.Extensions); ef != nil {
|
||||
return ef.SelectionCriteria
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOfficialLanguages returns official languages from tender terms extensions.
|
||||
func (pin PriorInformationNotice) GetOfficialLanguages() []string {
|
||||
if pin.firstLot() != nil &&
|
||||
pin.firstLot().TenderingTerms != nil &&
|
||||
len(pin.firstLot().TenderingTerms.CallForTendersDocumentReference) > 0 &&
|
||||
pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions != nil &&
|
||||
pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension != nil &&
|
||||
pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent != nil &&
|
||||
pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension != nil &&
|
||||
pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages != nil {
|
||||
|
||||
langs := pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages.Language
|
||||
languages := make([]string, len(langs))
|
||||
for i, lang := range langs {
|
||||
languages[i] = lang.ID
|
||||
}
|
||||
return languages
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDocumentURI returns the document URI from call for tenders document reference.
|
||||
func (pin PriorInformationNotice) GetDocumentURI() string {
|
||||
if pin.firstLot() != nil &&
|
||||
pin.firstLot().TenderingTerms != nil &&
|
||||
len(pin.firstLot().TenderingTerms.CallForTendersDocumentReference) > 0 &&
|
||||
pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].Attachment != nil &&
|
||||
pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].Attachment.ExternalReference != nil {
|
||||
return pin.firstLot().TenderingTerms.CallForTendersDocumentReference[0].Attachment.ExternalReference.URI
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetTenderDeadline returns the tender submission deadline.
|
||||
func (pin PriorInformationNotice) GetTenderDeadline() string {
|
||||
if pin.firstLot() != nil &&
|
||||
pin.firstLot().TenderingProcess != nil &&
|
||||
pin.firstLot().TenderingProcess.TenderSubmissionDeadlinePeriod != nil {
|
||||
return pin.firstLot().TenderingProcess.TenderSubmissionDeadlinePeriod.EndDate
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetBudget returns the estimated contract amount and currency.
|
||||
func (pin PriorInformationNotice) GetBudget() (amount string, currency string) {
|
||||
if pin.firstLot() != nil &&
|
||||
pin.firstLot().ProcurementProject != nil &&
|
||||
pin.firstLot().ProcurementProject.RequestedTenderTotal != nil {
|
||||
contractAmount := pin.firstLot().ProcurementProject.RequestedTenderTotal.EstimatedOverallContractAmount
|
||||
return contractAmount.Text, contractAmount.CurrencyID
|
||||
}
|
||||
if pin.ProcurementProject != nil && pin.ProcurementProject.RequestedTenderTotal != nil {
|
||||
a := pin.ProcurementProject.RequestedTenderTotal.EstimatedOverallContractAmount
|
||||
return a.Text, a.CurrencyID
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
// GetDuration returns the contract duration and unit.
|
||||
func (pin PriorInformationNotice) GetDuration() (duration string, unit string) {
|
||||
if pin.firstLot() != nil &&
|
||||
pin.firstLot().ProcurementProject != nil &&
|
||||
pin.firstLot().ProcurementProject.PlannedPeriod != nil &&
|
||||
pin.firstLot().ProcurementProject.PlannedPeriod.DurationMeasure != nil {
|
||||
durationMeasure := pin.firstLot().ProcurementProject.PlannedPeriod.DurationMeasure
|
||||
return durationMeasure.Text, durationMeasure.UnitCode
|
||||
}
|
||||
if pin.ProcurementProject != nil &&
|
||||
pin.ProcurementProject.PlannedPeriod != nil &&
|
||||
pin.ProcurementProject.PlannedPeriod.DurationMeasure != nil {
|
||||
dm := pin.ProcurementProject.PlannedPeriod.DurationMeasure
|
||||
return dm.Text, dm.UnitCode
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func (pin PriorInformationNotice) GetLanguage() string {
|
||||
@@ -1288,6 +1563,9 @@ type CurrencyText struct {
|
||||
type MainCommodityClassification struct {
|
||||
XMLName xml.Name `xml:"MainCommodityClassification"`
|
||||
ItemClassificationCode string `xml:"ItemClassificationCode"`
|
||||
ItemClassificationName string `xml:"ItemClassificationName,omitempty"`
|
||||
ItemClassificationDesc string `xml:"ItemClassificationDescription,omitempty"`
|
||||
Name string `xml:"Name,omitempty"`
|
||||
}
|
||||
|
||||
// AdditionalCommodityClassification contains additional commodity classification
|
||||
@@ -1451,34 +1729,24 @@ func (cn ContractNotice) GetLanguage() string {
|
||||
|
||||
// GetPublicationInfo returns publication information if available
|
||||
func (cn ContractNotice) GetPublicationInfo() *Publication {
|
||||
if cn.Extensions != nil &&
|
||||
cn.Extensions.UBLExtension != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
|
||||
return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.Publication
|
||||
if ef := ublEformsExtension(cn.Extensions); ef != nil {
|
||||
return ef.Publication
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOrganizations returns organizations from extensions
|
||||
func (cn ContractNotice) GetOrganizations() *Organizations {
|
||||
if cn.Extensions != nil &&
|
||||
cn.Extensions.UBLExtension != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
|
||||
return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.Organizations
|
||||
if ef := ublEformsExtension(cn.Extensions); ef != nil {
|
||||
return ef.Organizations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNoticeSubType returns the notice subtype code from extensions
|
||||
func (cn ContractNotice) GetNoticeSubType() string {
|
||||
if cn.Extensions != nil &&
|
||||
cn.Extensions.UBLExtension != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType != nil {
|
||||
return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType.SubTypeCode
|
||||
if ef := ublEformsExtension(cn.Extensions); ef != nil && ef.NoticeSubType != nil {
|
||||
return ef.NoticeSubType.SubTypeCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1592,6 +1860,26 @@ func (cn ContractNotice) GetMainClassification() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func mainCommodityClassificationLabel(m *MainCommodityClassification) string {
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
for _, s := range []string{m.ItemClassificationName, m.ItemClassificationDesc, m.Name} {
|
||||
if v := strings.TrimSpace(s); v != "" {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetMainClassificationDescription returns the CPV / item classification description when present in the notice XML.
|
||||
func (cn ContractNotice) GetMainClassificationDescription() string {
|
||||
if cn.ProcurementProject == nil {
|
||||
return ""
|
||||
}
|
||||
return mainCommodityClassificationLabel(cn.ProcurementProject.MainCommodityClassification)
|
||||
}
|
||||
|
||||
// GetPlaceOfPerformance returns the place of performance
|
||||
func (cn ContractNotice) GetPlaceOfPerformance() string {
|
||||
if cn.ProcurementProject != nil &&
|
||||
@@ -1612,11 +1900,8 @@ func (cn ContractNotice) GetLotID() string {
|
||||
|
||||
// GetSelectionCriteria returns selection criteria from extensions
|
||||
func (cn ContractNotice) GetSelectionCriteria() []SelectionCriteria {
|
||||
if cn.Extensions != nil &&
|
||||
cn.Extensions.UBLExtension != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent != nil &&
|
||||
cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
|
||||
return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.SelectionCriteria
|
||||
if ef := ublEformsExtension(cn.Extensions); ef != nil {
|
||||
return ef.SelectionCriteria
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1913,6 +2198,19 @@ func (can ContractAwardNotice) GetMainClassification() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetMainClassificationDescription returns the CPV / item classification description when present in the notice XML.
|
||||
func (can ContractAwardNotice) GetMainClassificationDescription() string {
|
||||
if can.ProcurementProject != nil {
|
||||
if s := mainCommodityClassificationLabel(can.ProcurementProject.MainCommodityClassification); s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
if lot := can.firstAwardLot(); lot != nil && lot.ProcurementProject != nil {
|
||||
return mainCommodityClassificationLabel(lot.ProcurementProject.MainCommodityClassification)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetTotalAwardValue returns the total award amount and currency
|
||||
func (can ContractAwardNotice) GetTotalAwardValue() (amount string, currency string) {
|
||||
noticeResult := can.GetNoticeResult()
|
||||
|
||||
Reference in New Issue
Block a user