2275 lines
96 KiB
Go
2275 lines
96 KiB
Go
package ted
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// NoticeTypeCodeField captures cbc:NoticeTypeCode: inner text (notice type, BT-02) and listName (form type, BT-03).
|
|
type NoticeTypeCodeField struct {
|
|
ListName string `xml:"listName,attr,omitempty"`
|
|
Text string `xml:",chardata"`
|
|
}
|
|
|
|
// DocumentType represents the type of TED document
|
|
type DocumentType string
|
|
|
|
// Document type constants for all supported TED XML notice types
|
|
const (
|
|
DocumentTypeContractNotice DocumentType = "ContractNotice"
|
|
DocumentTypeContractAwardNotice DocumentType = "ContractAwardNotice"
|
|
DocumentTypePriorInformationNotice DocumentType = "PriorInformationNotice"
|
|
DocumentTypeBusinessRegistrationInformationNotice DocumentType = "BusinessRegistrationInformationNotice"
|
|
)
|
|
|
|
// ParsedDocument wraps any TED document with type information
|
|
type ParsedDocument struct {
|
|
Type DocumentType
|
|
ContractNotice *ContractNotice `json:"contract_notice,omitempty"`
|
|
ContractAwardNotice *ContractAwardNotice `json:"contract_award_notice,omitempty"`
|
|
PriorInformationNotice *PriorInformationNotice `json:"prior_information_notice,omitempty"`
|
|
// BusinessRegistrationInformationNotice *BusinessRegistrationInformationNotice `json:"business_registration_information_notice,omitempty"`
|
|
}
|
|
|
|
// GetDocument returns the underlying document interface
|
|
func (pd *ParsedDocument) GetDocument() TEDDocument {
|
|
switch pd.Type {
|
|
case DocumentTypeContractNotice:
|
|
return pd.ContractNotice
|
|
case DocumentTypeContractAwardNotice:
|
|
return pd.ContractAwardNotice
|
|
case DocumentTypePriorInformationNotice:
|
|
return pd.PriorInformationNotice
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// TEDDocument represents the common interface for all TED document types
|
|
type TEDDocument interface {
|
|
GetID() string
|
|
GetNoticeType() string
|
|
GetLanguage() string
|
|
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"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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 NoticeTypeCodeField `xml:"NoticeTypeCode,omitempty"`
|
|
NoticeLanguageCode string `xml:"NoticeLanguageCode"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
AdditionalDocumentReference []AdditionalDocumentReference `xml:"AdditionalDocumentReference,omitempty"`
|
|
}
|
|
|
|
// Interface methods for PriorInformationNotice
|
|
func (pin PriorInformationNotice) GetID() string {
|
|
return pin.ID
|
|
}
|
|
|
|
func (pin PriorInformationNotice) GetNoticeType() string {
|
|
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 {
|
|
return pin.NoticeLanguageCode
|
|
}
|
|
|
|
func (pin PriorInformationNotice) Validate() error {
|
|
if pin.ID == "" {
|
|
return fmt.Errorf("prior information notice ID is required")
|
|
}
|
|
if pin.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DesignContest represents a design contest notice
|
|
type DesignContest struct {
|
|
XMLName xml.Name `xml:"DesignContest"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ContestDesignJury *ContestDesignJury `xml:"ContestDesignJury,omitempty"`
|
|
ContestDesignReward []ContestDesignReward `xml:"ContestDesignReward,omitempty"`
|
|
}
|
|
|
|
// Interface methods for DesignContest
|
|
func (dc DesignContest) GetID() string { return dc.ID }
|
|
func (dc DesignContest) GetNoticeType() string { return dc.NoticeTypeCode }
|
|
func (dc DesignContest) GetLanguage() string { return dc.NoticeLanguageCode }
|
|
func (dc DesignContest) Validate() error {
|
|
if dc.ID == "" {
|
|
return fmt.Errorf("design contest ID is required")
|
|
}
|
|
if dc.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// QualificationSystemNotice represents a qualification system notice
|
|
type QualificationSystemNotice struct {
|
|
XMLName xml.Name `xml:"QualificationSystemNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
QualificationApplication []QualificationApplication `xml:"QualificationApplication,omitempty"`
|
|
}
|
|
|
|
// Interface methods for QualificationSystemNotice
|
|
func (qsn QualificationSystemNotice) GetID() string { return qsn.ID }
|
|
func (qsn QualificationSystemNotice) GetNoticeType() string { return qsn.NoticeTypeCode }
|
|
func (qsn QualificationSystemNotice) GetLanguage() string { return qsn.NoticeLanguageCode }
|
|
func (qsn QualificationSystemNotice) Validate() error {
|
|
if qsn.ID == "" {
|
|
return fmt.Errorf("qualification system notice ID is required")
|
|
}
|
|
if qsn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ConcessionNotice represents a concession notice
|
|
type ConcessionNotice struct {
|
|
XMLName xml.Name `xml:"ConcessionNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
ConcessionRevenue *ConcessionRevenue `xml:"ConcessionRevenue,omitempty"`
|
|
ConcessionTerm *ConcessionTerm `xml:"ConcessionTerm,omitempty"`
|
|
}
|
|
|
|
// Interface methods for ConcessionNotice
|
|
func (cn ConcessionNotice) GetID() string { return cn.ID }
|
|
func (cn ConcessionNotice) GetNoticeType() string { return cn.NoticeTypeCode }
|
|
func (cn ConcessionNotice) GetLanguage() string { return cn.NoticeLanguageCode }
|
|
func (cn ConcessionNotice) Validate() error {
|
|
if cn.ID == "" {
|
|
return fmt.Errorf("concession notice ID is required")
|
|
}
|
|
if cn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PlanningNotice represents a planning notice
|
|
type PlanningNotice struct {
|
|
XMLName xml.Name `xml:"PlanningNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
BudgetAccountLine []BudgetAccountLine `xml:"BudgetAccountLine,omitempty"`
|
|
PlannedPeriod *PlannedPeriod `xml:"PlannedPeriod,omitempty"`
|
|
}
|
|
|
|
// Interface methods for PlanningNotice
|
|
func (pn PlanningNotice) GetID() string { return pn.ID }
|
|
func (pn PlanningNotice) GetNoticeType() string { return pn.NoticeTypeCode }
|
|
func (pn PlanningNotice) GetLanguage() string { return pn.NoticeLanguageCode }
|
|
func (pn PlanningNotice) Validate() error {
|
|
if pn.ID == "" {
|
|
return fmt.Errorf("planning notice ID is required")
|
|
}
|
|
if pn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CompetitionNotice represents a competition notice
|
|
type CompetitionNotice struct {
|
|
XMLName xml.Name `xml:"CompetitionNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
}
|
|
|
|
// Interface methods for CompetitionNotice
|
|
func (cn CompetitionNotice) GetID() string { return cn.ID }
|
|
func (cn CompetitionNotice) GetNoticeType() string { return cn.NoticeTypeCode }
|
|
func (cn CompetitionNotice) GetLanguage() string { return cn.NoticeLanguageCode }
|
|
func (cn CompetitionNotice) Validate() error {
|
|
if cn.ID == "" {
|
|
return fmt.Errorf("competition notice ID is required")
|
|
}
|
|
if cn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ResultNotice represents a result notice (eForms specific)
|
|
type ResultNotice struct {
|
|
XMLName xml.Name `xml:"ResultNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
TenderResult []TenderResult `xml:"TenderResult,omitempty"`
|
|
SettledContract []SettledContract `xml:"SettledContract,omitempty"`
|
|
}
|
|
|
|
// Interface methods for ResultNotice
|
|
func (rn ResultNotice) GetID() string { return rn.ID }
|
|
func (rn ResultNotice) GetNoticeType() string { return rn.NoticeTypeCode }
|
|
func (rn ResultNotice) GetLanguage() string { return rn.NoticeLanguageCode }
|
|
func (rn ResultNotice) Validate() error {
|
|
if rn.ID == "" {
|
|
return fmt.Errorf("result notice ID is required")
|
|
}
|
|
if rn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ChangeNotice represents a change notice (eForms specific)
|
|
type ChangeNotice struct {
|
|
XMLName xml.Name `xml:"ChangeNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
NoticeVersionIdentifier string `xml:"NoticeVersionIdentifier,omitempty"`
|
|
ChangeReason []ChangeReason `xml:"ChangeReason,omitempty"`
|
|
}
|
|
|
|
// Interface methods for ChangeNotice
|
|
func (cn ChangeNotice) GetID() string { return cn.ID }
|
|
func (cn ChangeNotice) GetNoticeType() string { return cn.NoticeTypeCode }
|
|
func (cn ChangeNotice) GetLanguage() string { return cn.NoticeLanguageCode }
|
|
func (cn ChangeNotice) Validate() error {
|
|
if cn.ID == "" {
|
|
return fmt.Errorf("change notice ID is required")
|
|
}
|
|
if cn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SubcontractNotice represents a subcontract notice
|
|
type SubcontractNotice struct {
|
|
XMLName xml.Name `xml:"SubcontractNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
SubcontractCall []SubcontractCall `xml:"SubcontractCall,omitempty"`
|
|
ParentContract *ParentContract `xml:"ParentContract,omitempty"`
|
|
}
|
|
|
|
// Interface methods for SubcontractNotice
|
|
func (sn SubcontractNotice) GetID() string { return sn.ID }
|
|
func (sn SubcontractNotice) GetNoticeType() string { return sn.NoticeTypeCode }
|
|
func (sn SubcontractNotice) GetLanguage() string { return sn.NoticeLanguageCode }
|
|
func (sn SubcontractNotice) Validate() error {
|
|
if sn.ID == "" {
|
|
return fmt.Errorf("subcontract notice ID is required")
|
|
}
|
|
if sn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Additional structures for new notice types
|
|
|
|
// ContestDesignJury contains design contest jury information
|
|
type ContestDesignJury struct {
|
|
XMLName xml.Name `xml:"ContestDesignJury"`
|
|
JuryDecisionDate string `xml:"JuryDecisionDate,omitempty"`
|
|
JuryDecision string `xml:"JuryDecision,omitempty"`
|
|
JuryMember []JuryMember `xml:"JuryMember,omitempty"`
|
|
JudgingCriteria *JudgingCriteria `xml:"JudgingCriteria,omitempty"`
|
|
}
|
|
|
|
// ContestDesignReward contains design contest reward information
|
|
type ContestDesignReward struct {
|
|
XMLName xml.Name `xml:"ContestDesignReward"`
|
|
RewardCode string `xml:"RewardCode,omitempty"`
|
|
Benefit *Benefit `xml:"Benefit,omitempty"`
|
|
}
|
|
|
|
// JuryMember contains jury member information
|
|
type JuryMember struct {
|
|
XMLName xml.Name `xml:"JuryMember"`
|
|
Party *Party `xml:"Party,omitempty"`
|
|
}
|
|
|
|
// JudgingCriteria contains judging criteria information
|
|
type JudgingCriteria struct {
|
|
XMLName xml.Name `xml:"JudgingCriteria"`
|
|
Description string `xml:"Description,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
}
|
|
|
|
// Benefit contains benefit information
|
|
type Benefit struct {
|
|
XMLName xml.Name `xml:"Benefit"`
|
|
BenefitValue CurrencyText `xml:"BenefitValue,omitempty"`
|
|
}
|
|
|
|
// QualificationApplication contains qualification application information
|
|
type QualificationApplication struct {
|
|
XMLName xml.Name `xml:"QualificationApplication"`
|
|
QualificationTypeCode string `xml:"QualificationTypeCode,omitempty"`
|
|
ApplicationPeriod *ApplicationPeriod `xml:"ApplicationPeriod,omitempty"`
|
|
TendererQualificationRequest *TendererQualificationRequest `xml:"TendererQualificationRequest,omitempty"`
|
|
}
|
|
|
|
// ApplicationPeriod contains application period information
|
|
type ApplicationPeriod struct {
|
|
XMLName xml.Name `xml:"ApplicationPeriod"`
|
|
StartDate string `xml:"StartDate,omitempty"`
|
|
EndDate string `xml:"EndDate,omitempty"`
|
|
StartTime string `xml:"StartTime,omitempty"`
|
|
EndTime string `xml:"EndTime,omitempty"`
|
|
}
|
|
|
|
// ConcessionRevenue contains concession revenue information
|
|
type ConcessionRevenue struct {
|
|
XMLName xml.Name `xml:"ConcessionRevenue"`
|
|
RevenueType string `xml:"RevenueType,omitempty"`
|
|
RevenueAmount CurrencyText `xml:"RevenueAmount,omitempty"`
|
|
}
|
|
|
|
// ConcessionTerm contains concession term information
|
|
type ConcessionTerm struct {
|
|
XMLName xml.Name `xml:"ConcessionTerm"`
|
|
ConcessionValue CurrencyText `xml:"ConcessionValue,omitempty"`
|
|
Duration *DurationMeasure `xml:"DurationMeasure,omitempty"`
|
|
}
|
|
|
|
// BudgetAccountLine contains budget account line information
|
|
type BudgetAccountLine struct {
|
|
XMLName xml.Name `xml:"BudgetAccountLine"`
|
|
ID string `xml:"ID,omitempty"`
|
|
BudgetYear string `xml:"BudgetYear,omitempty"`
|
|
TotalAmount CurrencyText `xml:"TotalAmount,omitempty"`
|
|
BudgetAccount *BudgetAccount `xml:"BudgetAccount,omitempty"`
|
|
}
|
|
|
|
// BudgetAccount contains budget account information
|
|
type BudgetAccount struct {
|
|
XMLName xml.Name `xml:"BudgetAccount"`
|
|
BudgetCode string `xml:"BudgetCode,omitempty"`
|
|
RequiredClassificationScheme *RequiredClassificationScheme `xml:"RequiredClassificationScheme,omitempty"`
|
|
}
|
|
|
|
// RequiredClassificationScheme contains classification scheme information
|
|
type RequiredClassificationScheme struct {
|
|
XMLName xml.Name `xml:"RequiredClassificationScheme"`
|
|
ItemClassificationCode string `xml:"ItemClassificationCode,omitempty"`
|
|
}
|
|
|
|
// SubcontractCall contains subcontract call information
|
|
type SubcontractCall struct {
|
|
XMLName xml.Name `xml:"SubcontractCall"`
|
|
SubcontractingTypeCode string `xml:"SubcontractingTypeCode,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
}
|
|
|
|
// ParentContract contains parent contract information
|
|
type ParentContract struct {
|
|
XMLName xml.Name `xml:"ParentContract"`
|
|
ContractReference *ContractReference `xml:"ContractReference,omitempty"`
|
|
FrameworkAgreement *FrameworkAgreement `xml:"FrameworkAgreement,omitempty"`
|
|
}
|
|
|
|
// FrameworkAgreement contains framework agreement information
|
|
type FrameworkAgreement struct {
|
|
XMLName xml.Name `xml:"FrameworkAgreement"`
|
|
EstimatedMaximumValue CurrencyText `xml:"EstimatedMaximumValue,omitempty"`
|
|
MaximumParticipants string `xml:"MaximumParticipants,omitempty"`
|
|
Duration *DurationMeasure `xml:"DurationMeasure,omitempty"`
|
|
SubsequentProcedureIndicator string `xml:"SubsequentProcedureIndicator,omitempty"`
|
|
}
|
|
|
|
// AdditionalDocumentReference contains additional document reference information
|
|
type AdditionalDocumentReference struct {
|
|
XMLName xml.Name `xml:"AdditionalDocumentReference"`
|
|
ID string `xml:"ID,omitempty"`
|
|
DocumentType string `xml:"DocumentType,omitempty"`
|
|
DocumentDescription string `xml:"DocumentDescription,omitempty"`
|
|
LanguageID string `xml:"LanguageID,omitempty"`
|
|
Attachment *Attachment `xml:"Attachment,omitempty"`
|
|
ValidityPeriod *ValidityPeriod `xml:"ValidityPeriod,omitempty"`
|
|
UBLExtensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
}
|
|
|
|
// ValidityPeriod contains validity period information
|
|
type ValidityPeriod struct {
|
|
XMLName xml.Name `xml:"ValidityPeriod"`
|
|
StartDate string `xml:"StartDate,omitempty"`
|
|
EndDate string `xml:"EndDate,omitempty"`
|
|
StartTime string `xml:"StartTime,omitempty"`
|
|
EndTime string `xml:"EndTime,omitempty"`
|
|
}
|
|
|
|
// EnhancedTenderResult structure with more comprehensive information
|
|
type EnhancedTenderResult struct {
|
|
XMLName xml.Name `xml:"TenderResult"`
|
|
AwardDate string `xml:"AwardDate"`
|
|
AwardTime string `xml:"AwardTime,omitempty"`
|
|
ReceivedTenderQuantity string `xml:"ReceivedTenderQuantity,omitempty"`
|
|
LowerTenderAmount CurrencyText `xml:"LowerTenderAmount,omitempty"`
|
|
HigherTenderAmount CurrencyText `xml:"HigherTenderAmount,omitempty"`
|
|
AwardedTenderedProject *AwardedTenderedProject `xml:"AwardedTenderedProject,omitempty"`
|
|
ContractAwardNotice *ContractAwardNotice `xml:"ContractAwardNotice,omitempty"`
|
|
SubcontractingTerm []SubcontractingTerm `xml:"SubcontractingTerm,omitempty"`
|
|
WinningTenderLot []WinningTenderLot `xml:"WinningTenderLot,omitempty"`
|
|
ReceivedSubmissionsStatistics []ReceivedSubmissionsStatistics `xml:"ReceivedSubmissionsStatistics,omitempty"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
}
|
|
|
|
// AwardedTenderedProject contains awarded tendered project information
|
|
type AwardedTenderedProject struct {
|
|
XMLName xml.Name `xml:"AwardedTenderedProject"`
|
|
ProcurementTypeCode string `xml:"ProcurementTypeCode,omitempty"`
|
|
TotalAmount CurrencyText `xml:"TotalAmount,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
LegalMonetaryTotal *LegalMonetaryTotal `xml:"LegalMonetaryTotal,omitempty"`
|
|
TenderLot []TenderLot `xml:"TenderLot,omitempty"`
|
|
}
|
|
|
|
// WinningTenderLot contains winning tender lot information
|
|
type WinningTenderLot struct {
|
|
XMLName xml.Name `xml:"WinningTenderLot"`
|
|
TenderLot *TenderLot `xml:"TenderLot,omitempty"`
|
|
WinningTender []WinningTender `xml:"WinningTender,omitempty"`
|
|
}
|
|
|
|
// WinningTender contains winning tender information
|
|
type WinningTender struct {
|
|
XMLName xml.Name `xml:"WinningTender"`
|
|
ID string `xml:"ID"`
|
|
TenderVariantIndicator string `xml:"TenderVariantIndicator,omitempty"`
|
|
LegalMonetaryTotal *LegalMonetaryTotal `xml:"LegalMonetaryTotal,omitempty"`
|
|
TenderingParty *TenderingParty `xml:"TenderingParty,omitempty"`
|
|
SubcontractingTerm []SubcontractingTerm `xml:"SubcontractingTerm,omitempty"`
|
|
}
|
|
|
|
// Enhanced SubcontractingTerm structure
|
|
type SubcontractingTerm struct {
|
|
XMLName xml.Name `xml:"SubcontractingTerm"`
|
|
TermCode string `xml:"TermCode"`
|
|
Amount CurrencyText `xml:"Amount,omitempty"`
|
|
Rate string `xml:"Rate,omitempty"`
|
|
Description string `xml:"Description,omitempty"`
|
|
UnknownPriceIndicator string `xml:"UnknownPriceIndicator,omitempty"`
|
|
SubcontractingDescription string `xml:"SubcontractingDescription,omitempty"`
|
|
}
|
|
|
|
// ContractNotice represents the main TED XML contract notice structure
|
|
type ContractNotice struct {
|
|
XMLName xml.Name `xml:"ContractNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
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 NoticeTypeCodeField `xml:"NoticeTypeCode,omitempty"`
|
|
NoticeLanguageCode string `xml:"NoticeLanguageCode"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLots []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
}
|
|
|
|
func (cn ContractNotice) firstLot() *ProcurementProjectLot {
|
|
if len(cn.ProcurementProjectLots) == 0 {
|
|
return nil
|
|
}
|
|
return &cn.ProcurementProjectLots[0]
|
|
}
|
|
|
|
// ContractAwardNotice represents the main TED XML contract award notice structure
|
|
type ContractAwardNotice struct {
|
|
XMLName xml.Name `xml:"ContractAwardNotice"`
|
|
Xmlns string `xml:"xmlns,attr,omitempty"`
|
|
XmlnsCac string `xml:"xmlns:cac,attr,omitempty"`
|
|
XmlnsCbc string `xml:"xmlns:cbc,attr,omitempty"`
|
|
XmlnsEfac string `xml:"xmlns:efac,attr,omitempty"`
|
|
XmlnsEfbc string `xml:"xmlns:efbc,attr,omitempty"`
|
|
XmlnsEfext string `xml:"xmlns:efext,attr,omitempty"`
|
|
XmlnsExt string `xml:"xmlns:ext,attr,omitempty"`
|
|
Extensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
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 NoticeTypeCodeField `xml:"NoticeTypeCode,omitempty"`
|
|
NoticeLanguageCode string `xml:"NoticeLanguageCode"`
|
|
ContractingParty *ContractingParty `xml:"ContractingParty,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
|
|
TenderResult *TenderResult `xml:"TenderResult,omitempty"`
|
|
}
|
|
|
|
func (can ContractAwardNotice) firstAwardLot() *ProcurementProjectLot {
|
|
if len(can.ProcurementProjectLot) == 0 {
|
|
return nil
|
|
}
|
|
return &can.ProcurementProjectLot[0]
|
|
}
|
|
|
|
func pickWinningLotTender(lotTenders []LotTender) *LotTender {
|
|
if len(lotTenders) == 0 {
|
|
return nil
|
|
}
|
|
for i := range lotTenders {
|
|
if strings.TrimSpace(lotTenders[i].RankCode) == "1" {
|
|
return &lotTenders[i]
|
|
}
|
|
}
|
|
return &lotTenders[0]
|
|
}
|
|
|
|
// NoticeResult contains notice result information from extensions
|
|
type NoticeResult struct {
|
|
XMLName xml.Name `xml:"NoticeResult"`
|
|
TotalAmount *CurrencyText `xml:"TotalAmount,omitempty"`
|
|
LotResult []LotResult `xml:"LotResult,omitempty"`
|
|
}
|
|
|
|
// LotResult contains lot result information
|
|
type LotResult struct {
|
|
XMLName xml.Name `xml:"LotResult"`
|
|
ID string `xml:"ID"`
|
|
TenderResultCode string `xml:"TenderResultCode"`
|
|
LotTender []LotTender `xml:"LotTender,omitempty"`
|
|
ReceivedSubmissionsStatistics []ReceivedSubmissionsStatistics `xml:"ReceivedSubmissionsStatistics,omitempty"`
|
|
SettledContract []SettledContract `xml:"SettledContract,omitempty"`
|
|
TenderLot *TenderLot `xml:"TenderLot,omitempty"`
|
|
}
|
|
|
|
// LotTender contains lot tender information
|
|
type LotTender struct {
|
|
XMLName xml.Name `xml:"LotTender"`
|
|
ID string `xml:"ID"`
|
|
RankCode string `xml:"RankCode,omitempty"`
|
|
TenderRankedIndicator string `xml:"TenderRankedIndicator,omitempty"`
|
|
TenderVariantIndicator string `xml:"TenderVariantIndicator,omitempty"`
|
|
LegalMonetaryTotal *LegalMonetaryTotal `xml:"LegalMonetaryTotal,omitempty"`
|
|
SubcontractingTerm *SubcontractingTerm `xml:"SubcontractingTerm,omitempty"`
|
|
TenderingParty *TenderingParty `xml:"TenderingParty,omitempty"`
|
|
TenderLot *TenderLot `xml:"TenderLot,omitempty"`
|
|
TenderReference *TenderReference `xml:"TenderReference,omitempty"`
|
|
}
|
|
|
|
// LegalMonetaryTotal contains monetary total information
|
|
type LegalMonetaryTotal struct {
|
|
XMLName xml.Name `xml:"LegalMonetaryTotal"`
|
|
PayableAmount CurrencyText `xml:"PayableAmount"`
|
|
}
|
|
|
|
// TenderingParty contains tendering party information
|
|
type TenderingParty struct {
|
|
XMLName xml.Name `xml:"TenderingParty"`
|
|
ID string `xml:"ID"`
|
|
}
|
|
|
|
// TenderLot contains tender lot information
|
|
type TenderLot struct {
|
|
XMLName xml.Name `xml:"TenderLot"`
|
|
ID string `xml:"ID"`
|
|
}
|
|
|
|
// TenderReference contains tender reference information
|
|
type TenderReference struct {
|
|
XMLName xml.Name `xml:"TenderReference"`
|
|
ID string `xml:"ID"`
|
|
}
|
|
|
|
// ReceivedSubmissionsStatistics contains received submissions statistics
|
|
type ReceivedSubmissionsStatistics struct {
|
|
XMLName xml.Name `xml:"ReceivedSubmissionsStatistics"`
|
|
StatisticsCode string `xml:"StatisticsCode"`
|
|
StatisticsNumeric string `xml:"StatisticsNumeric"`
|
|
}
|
|
|
|
// SettledContract contains settled contract information
|
|
type SettledContract struct {
|
|
XMLName xml.Name `xml:"SettledContract"`
|
|
ID string `xml:"ID"`
|
|
IssueDate string `xml:"IssueDate,omitempty"`
|
|
Title string `xml:"Title,omitempty"`
|
|
SignatoryParty *SignatoryParty `xml:"SignatoryParty,omitempty"`
|
|
ContractReference *ContractReference `xml:"ContractReference,omitempty"`
|
|
LotTender *LotTender `xml:"LotTender,omitempty"`
|
|
}
|
|
|
|
// SignatoryParty contains signatory party information
|
|
type SignatoryParty struct {
|
|
XMLName xml.Name `xml:"SignatoryParty"`
|
|
PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
|
|
}
|
|
|
|
// ContractReference contains contract reference information
|
|
type ContractReference struct {
|
|
XMLName xml.Name `xml:"ContractReference"`
|
|
ID string `xml:"ID"`
|
|
}
|
|
|
|
// TenderResult contains tender result information
|
|
type TenderResult struct {
|
|
XMLName xml.Name `xml:"TenderResult"`
|
|
AwardDate string `xml:"AwardDate"`
|
|
}
|
|
|
|
// NoticeDocumentReference contains notice document reference information
|
|
type NoticeDocumentReference struct {
|
|
XMLName xml.Name `xml:"NoticeDocumentReference"`
|
|
ID string `xml:"ID"`
|
|
}
|
|
|
|
// PresentationPeriod contains presentation period information
|
|
type PresentationPeriod struct {
|
|
XMLName xml.Name `xml:"PresentationPeriod"`
|
|
Description string `xml:"Description,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
}
|
|
|
|
// AppealInformationParty contains appeal information party
|
|
type AppealInformationParty struct {
|
|
XMLName xml.Name `xml:"AppealInformationParty"`
|
|
PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
|
|
}
|
|
|
|
// MediationParty contains mediation party information
|
|
type MediationParty struct {
|
|
XMLName xml.Name `xml:"MediationParty"`
|
|
PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
|
|
}
|
|
|
|
// UBLExtensions contains eForms extensions
|
|
type UBLExtensions struct {
|
|
XMLName xml.Name `xml:"UBLExtensions"`
|
|
UBLExtension *UBLExtension `xml:"UBLExtension,omitempty"`
|
|
}
|
|
|
|
// UBLExtension contains extension content
|
|
type UBLExtension struct {
|
|
XMLName xml.Name `xml:"UBLExtension"`
|
|
ExtensionContent *ExtensionContent `xml:"ExtensionContent,omitempty"`
|
|
}
|
|
|
|
// ExtensionContent contains eForms extension data
|
|
type ExtensionContent struct {
|
|
XMLName xml.Name `xml:"ExtensionContent"`
|
|
EformsExtension *EformsExtension `xml:"EformsExtension,omitempty"`
|
|
TransmissionDate string `xml:"TransmissionDate,omitempty"`
|
|
TransmissionTime string `xml:"TransmissionTime,omitempty"`
|
|
}
|
|
|
|
// EformsExtension contains eForms specific data
|
|
type EformsExtension struct {
|
|
XMLName xml.Name `xml:"EformsExtension"`
|
|
NoticeResult *NoticeResult `xml:"NoticeResult,omitempty"`
|
|
NoticeSubType *NoticeSubType `xml:"NoticeSubType,omitempty"`
|
|
Organizations *Organizations `xml:"Organizations,omitempty"`
|
|
Publication *Publication `xml:"Publication,omitempty"`
|
|
Changes *Changes `xml:"Changes,omitempty"`
|
|
SelectionCriteria []SelectionCriteria `xml:"SelectionCriteria,omitempty"`
|
|
OfficialLanguages *OfficialLanguages `xml:"OfficialLanguages,omitempty"`
|
|
AwardCriterionParameter *AwardCriterionParameter `xml:"AwardCriterionParameter,omitempty"`
|
|
AccessToolName string `xml:"AccessToolName,omitempty"`
|
|
TransmissionDate string `xml:"TransmissionDate,omitempty"`
|
|
TransmissionTime string `xml:"TransmissionTime,omitempty"`
|
|
}
|
|
|
|
// NoticeSubType contains notice subtype information
|
|
type NoticeSubType struct {
|
|
XMLName xml.Name `xml:"NoticeSubType"`
|
|
SubTypeCode string `xml:"SubTypeCode"`
|
|
}
|
|
|
|
// SelectionCriteria contains tenderer requirement information
|
|
type SelectionCriteria struct {
|
|
XMLName xml.Name `xml:"SelectionCriteria"`
|
|
CriterionTypeCode string `xml:"CriterionTypeCode"`
|
|
TendererRequirementTypeCode string `xml:"TendererRequirementTypeCode"`
|
|
Name string `xml:"Name,omitempty"`
|
|
Description string `xml:"Description,omitempty"`
|
|
CalculationExpressionCode string `xml:"CalculationExpressionCode,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
}
|
|
|
|
// OfficialLanguages contains official language information
|
|
type OfficialLanguages struct {
|
|
XMLName xml.Name `xml:"OfficialLanguages"`
|
|
Language []Language `xml:"Language"`
|
|
}
|
|
|
|
// Language represents a language entry
|
|
type Language struct {
|
|
XMLName xml.Name `xml:"Language"`
|
|
ID string `xml:"ID"`
|
|
}
|
|
|
|
// Organizations contains organization information
|
|
type Organizations struct {
|
|
XMLName xml.Name `xml:"Organizations"`
|
|
Organization []Organization `xml:"Organization"`
|
|
}
|
|
|
|
// Organization represents an organization entity
|
|
type Organization struct {
|
|
XMLName xml.Name `xml:"Organization"`
|
|
NaturalPersonIndicator string `xml:"NaturalPersonIndicator,omitempty"`
|
|
Company *Company `xml:"Company,omitempty"`
|
|
}
|
|
|
|
// Company represents company informationf
|
|
type Company struct {
|
|
XMLName xml.Name `xml:"Company"`
|
|
WebsiteURI string `xml:"WebsiteURI,omitempty"`
|
|
PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
|
|
PartyName *PartyName `xml:"PartyName,omitempty"`
|
|
PostalAddress *PostalAddress `xml:"PostalAddress,omitempty"`
|
|
PartyLegalEntity *PartyLegalEntity `xml:"PartyLegalEntity,omitempty"`
|
|
Contact *Contact `xml:"Contact,omitempty"`
|
|
}
|
|
|
|
// PartyIdentification contains party ID information
|
|
type PartyIdentification struct {
|
|
XMLName xml.Name `xml:"PartyIdentification"`
|
|
ID string `xml:"ID"`
|
|
}
|
|
|
|
// PartyName contains party name
|
|
type PartyName struct {
|
|
XMLName xml.Name `xml:"PartyName"`
|
|
Name string `xml:"Name"`
|
|
}
|
|
|
|
// PostalAddress contains address information
|
|
type PostalAddress struct {
|
|
XMLName xml.Name `xml:"PostalAddress"`
|
|
StreetName string `xml:"StreetName,omitempty"`
|
|
CityName string `xml:"CityName,omitempty"`
|
|
PostalZone string `xml:"PostalZone,omitempty"`
|
|
CountrySubentity string `xml:"CountrySubentity,omitempty"`
|
|
CountrySubentityCode string `xml:"CountrySubentityCode,omitempty"`
|
|
Department string `xml:"Department,omitempty"`
|
|
Country *Country `xml:"Country,omitempty"`
|
|
}
|
|
|
|
// Country contains country information
|
|
type Country struct {
|
|
XMLName xml.Name `xml:"Country"`
|
|
IdentificationCode string `xml:"IdentificationCode"`
|
|
}
|
|
|
|
// PartyLegalEntity contains legal entity information
|
|
type PartyLegalEntity struct {
|
|
XMLName xml.Name `xml:"PartyLegalEntity"`
|
|
CompanyID string `xml:"CompanyID"`
|
|
}
|
|
|
|
// Contact contains contact information
|
|
type Contact struct {
|
|
XMLName xml.Name `xml:"Contact"`
|
|
Name string `xml:"Name,omitempty"`
|
|
Telephone string `xml:"Telephone,omitempty"`
|
|
Telefax string `xml:"Telefax,omitempty"`
|
|
ElectronicMail string `xml:"ElectronicMail,omitempty"`
|
|
}
|
|
|
|
// Publication contains publication information
|
|
type Publication struct {
|
|
XMLName xml.Name `xml:"Publication"`
|
|
NoticePublicationID string `xml:"NoticePublicationID"`
|
|
GazetteID string `xml:"GazetteID"`
|
|
PublicationDate string `xml:"PublicationDate"`
|
|
}
|
|
|
|
// Changes contains notice change information
|
|
type Changes struct {
|
|
XMLName xml.Name `xml:"Changes"`
|
|
ChangedNoticeIdentifier string `xml:"ChangedNoticeIdentifier"`
|
|
ChangeReason *ChangeReason `xml:"ChangeReason,omitempty"`
|
|
}
|
|
|
|
// ChangeReason contains change reason information
|
|
type ChangeReason struct {
|
|
XMLName xml.Name `xml:"ChangeReason"`
|
|
ReasonCode string `xml:"ReasonCode"`
|
|
}
|
|
|
|
// ContractingParty contains contracting party information
|
|
type ContractingParty struct {
|
|
XMLName xml.Name `xml:"ContractingParty"`
|
|
BuyerProfileURI string `xml:"BuyerProfileURI,omitempty"`
|
|
ContractingPartyType *ContractingPartyType `xml:"ContractingPartyType,omitempty"`
|
|
ContractingActivity *ContractingActivity `xml:"ContractingActivity,omitempty"`
|
|
Party *Party `xml:"Party,omitempty"`
|
|
}
|
|
|
|
// ContractingPartyType contains party type information
|
|
type ContractingPartyType struct {
|
|
XMLName xml.Name `xml:"ContractingPartyType"`
|
|
PartyTypeCode string `xml:"PartyTypeCode"`
|
|
}
|
|
|
|
// ContractingActivity contains contracting activity information
|
|
type ContractingActivity struct {
|
|
XMLName xml.Name `xml:"ContractingActivity"`
|
|
ActivityTypeCode string `xml:"ActivityTypeCode"`
|
|
}
|
|
|
|
// Party contains party information
|
|
type Party struct {
|
|
XMLName xml.Name `xml:"Party"`
|
|
PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
|
|
ServiceProviderParty *ServiceProviderParty `xml:"ServiceProviderParty,omitempty"`
|
|
}
|
|
|
|
// ServiceProviderParty contains service provider information
|
|
type ServiceProviderParty struct {
|
|
XMLName xml.Name `xml:"ServiceProviderParty"`
|
|
ServiceTypeCode string `xml:"ServiceTypeCode,omitempty"`
|
|
Party *Party `xml:"Party,omitempty"`
|
|
}
|
|
|
|
// TenderingTerms contains tendering terms
|
|
type TenderingTerms struct {
|
|
XMLName xml.Name `xml:"TenderingTerms"`
|
|
VariantConstraintCode string `xml:"VariantConstraintCode,omitempty"`
|
|
FundingProgramCode string `xml:"FundingProgramCode,omitempty"`
|
|
RecurringProcurementIndicator string `xml:"RecurringProcurementIndicator,omitempty"`
|
|
MultipleTendersCode string `xml:"MultipleTendersCode,omitempty"`
|
|
TendererQualificationRequest []TendererQualificationRequest `xml:"TendererQualificationRequest,omitempty"`
|
|
AppealTerms *AppealTerms `xml:"AppealTerms,omitempty"`
|
|
CallForTendersDocumentReference []CallForTendersDocumentReference `xml:"CallForTendersDocumentReference,omitempty"`
|
|
RequiredFinancialGuarantee *RequiredFinancialGuarantee `xml:"RequiredFinancialGuarantee,omitempty"`
|
|
PaymentTerms *PaymentTerms `xml:"PaymentTerms,omitempty"`
|
|
AwardingTerms *AwardingTerms `xml:"AwardingTerms,omitempty"`
|
|
AdditionalInformationParty *AdditionalInformationParty `xml:"AdditionalInformationParty,omitempty"`
|
|
TenderRecipientParty *TenderRecipientParty `xml:"TenderRecipientParty,omitempty"`
|
|
TenderValidityPeriod *TenderValidityPeriod `xml:"TenderValidityPeriod,omitempty"`
|
|
Language *Language `xml:"Language,omitempty"`
|
|
PostAwardProcess *PostAwardProcess `xml:"PostAwardProcess,omitempty"`
|
|
ContractExecutionRequirement []ContractExecutionRequirement `xml:"ContractExecutionRequirement,omitempty"`
|
|
UBLExtensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
}
|
|
|
|
// RequiredFinancialGuarantee contains financial guarantee information
|
|
type RequiredFinancialGuarantee struct {
|
|
XMLName xml.Name `xml:"RequiredFinancialGuarantee"`
|
|
GuaranteeTypeCode string `xml:"GuaranteeTypeCode,omitempty"`
|
|
Description string `xml:"Description,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
}
|
|
|
|
// PaymentTerms contains payment terms information
|
|
type PaymentTerms struct {
|
|
XMLName xml.Name `xml:"PaymentTerms"`
|
|
Note string `xml:"Note,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
}
|
|
|
|
// AwardingTerms contains awarding terms information
|
|
type AwardingTerms struct {
|
|
XMLName xml.Name `xml:"AwardingTerms"`
|
|
AwardingCriterion []AwardingCriterion `xml:"AwardingCriterion,omitempty"`
|
|
}
|
|
|
|
// AwardingCriterion contains awarding criteria information
|
|
type AwardingCriterion struct {
|
|
XMLName xml.Name `xml:"AwardingCriterion"`
|
|
SubordinateAwardingCriterion []SubordinateAwardingCriterion `xml:"SubordinateAwardingCriterion,omitempty"`
|
|
}
|
|
|
|
// SubordinateAwardingCriterion contains subordinate awarding criteria
|
|
type SubordinateAwardingCriterion struct {
|
|
XMLName xml.Name `xml:"SubordinateAwardingCriterion"`
|
|
AwardingCriterionTypeCode string `xml:"AwardingCriterionTypeCode,omitempty"`
|
|
Name string `xml:"Name,omitempty"`
|
|
Description string `xml:"Description,omitempty"`
|
|
UBLExtensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
}
|
|
|
|
// AwardCriterionParameter contains award criterion parameter information
|
|
type AwardCriterionParameter struct {
|
|
XMLName xml.Name `xml:"AwardCriterionParameter"`
|
|
ParameterCode string `xml:"ParameterCode,omitempty"`
|
|
ParameterNumeric string `xml:"ParameterNumeric,omitempty"`
|
|
}
|
|
|
|
// AdditionalInformationParty contains additional information party
|
|
type AdditionalInformationParty struct {
|
|
XMLName xml.Name `xml:"AdditionalInformationParty"`
|
|
PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
|
|
}
|
|
|
|
// TenderRecipientParty contains tender recipient party information
|
|
type TenderRecipientParty struct {
|
|
XMLName xml.Name `xml:"TenderRecipientParty"`
|
|
EndpointID string `xml:"EndpointID,omitempty"`
|
|
}
|
|
|
|
// TenderValidityPeriod contains tender validity period
|
|
type TenderValidityPeriod struct {
|
|
XMLName xml.Name `xml:"TenderValidityPeriod"`
|
|
DurationMeasure *DurationMeasure `xml:"DurationMeasure,omitempty"`
|
|
}
|
|
|
|
// PostAwardProcess contains post award process information
|
|
type PostAwardProcess struct {
|
|
XMLName xml.Name `xml:"PostAwardProcess"`
|
|
ElectronicCatalogueUsageIndicator string `xml:"ElectronicCatalogueUsageIndicator,omitempty"`
|
|
ElectronicOrderUsageIndicator string `xml:"ElectronicOrderUsageIndicator,omitempty"`
|
|
ElectronicPaymentUsageIndicator string `xml:"ElectronicPaymentUsageIndicator,omitempty"`
|
|
}
|
|
|
|
// ContractExecutionRequirement contains contract execution requirements
|
|
type ContractExecutionRequirement struct {
|
|
XMLName xml.Name `xml:"ContractExecutionRequirement"`
|
|
ExecutionRequirementCode string `xml:"ExecutionRequirementCode,omitempty"`
|
|
Description string `xml:"Description,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
}
|
|
|
|
// AppealTerms contains appeal terms information
|
|
type AppealTerms struct {
|
|
XMLName xml.Name `xml:"AppealTerms"`
|
|
Description string `xml:"Description,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
PresentationPeriod *PresentationPeriod `xml:"PresentationPeriod,omitempty"`
|
|
AppealInformationParty *AppealInformationParty `xml:"AppealInformationParty,omitempty"`
|
|
AppealReceiverParty *AppealReceiverParty `xml:"AppealReceiverParty,omitempty"`
|
|
MediationParty *MediationParty `xml:"MediationParty,omitempty"`
|
|
}
|
|
|
|
// AppealReceiverParty contains appeal receiver party information
|
|
type AppealReceiverParty struct {
|
|
XMLName xml.Name `xml:"AppealReceiverParty"`
|
|
PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
|
|
}
|
|
|
|
// CallForTendersDocumentReference contains document reference information
|
|
type CallForTendersDocumentReference struct {
|
|
XMLName xml.Name `xml:"CallForTendersDocumentReference"`
|
|
ID string `xml:"ID,omitempty"`
|
|
DocumentType string `xml:"DocumentType,omitempty"`
|
|
LanguageID string `xml:"LanguageID,omitempty"`
|
|
DocumentStatusCode string `xml:"DocumentStatusCode,omitempty"`
|
|
Attachment *Attachment `xml:"Attachment,omitempty"`
|
|
UBLExtensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
}
|
|
|
|
// Attachment contains attachment information
|
|
type Attachment struct {
|
|
XMLName xml.Name `xml:"Attachment"`
|
|
ExternalReference *ExternalReference `xml:"ExternalReference,omitempty"`
|
|
}
|
|
|
|
// ExternalReference contains external reference information
|
|
type ExternalReference struct {
|
|
XMLName xml.Name `xml:"ExternalReference"`
|
|
URI string `xml:"URI"`
|
|
DocumentHash string `xml:"DocumentHash,omitempty"`
|
|
FileName string `xml:"FileName,omitempty"`
|
|
}
|
|
|
|
// TendererQualificationRequest contains qualification request information
|
|
type TendererQualificationRequest struct {
|
|
XMLName xml.Name `xml:"TendererQualificationRequest"`
|
|
CompanyLegalFormCode string `xml:"CompanyLegalFormCode,omitempty"`
|
|
SpecificTendererRequirement []SpecificTendererRequirement `xml:"SpecificTendererRequirement,omitempty"`
|
|
}
|
|
|
|
// SpecificTendererRequirement contains specific requirement information
|
|
type SpecificTendererRequirement struct {
|
|
XMLName xml.Name `xml:"SpecificTendererRequirement"`
|
|
TendererRequirementTypeCode string `xml:"TendererRequirementTypeCode"`
|
|
Description string `xml:"Description,omitempty"`
|
|
}
|
|
|
|
// TenderingProcess contains tendering process information
|
|
type TenderingProcess struct {
|
|
XMLName xml.Name `xml:"TenderingProcess"`
|
|
Description string `xml:"Description,omitempty"`
|
|
ProcedureCode string `xml:"ProcedureCode"`
|
|
SubmissionMethodCode string `xml:"SubmissionMethodCode,omitempty"`
|
|
GovernmentAgreementConstraintIndicator string `xml:"GovernmentAgreementConstraintIndicator,omitempty"`
|
|
ProcessJustification *ProcessJustification `xml:"ProcessJustification,omitempty"`
|
|
TenderSubmissionDeadlinePeriod *TenderSubmissionDeadlinePeriod `xml:"TenderSubmissionDeadlinePeriod,omitempty"`
|
|
OpenTenderEvent *OpenTenderEvent `xml:"OpenTenderEvent,omitempty"`
|
|
AuctionTerms *AuctionTerms `xml:"AuctionTerms,omitempty"`
|
|
ContractingSystem []ContractingSystem `xml:"ContractingSystem,omitempty"`
|
|
NoticeDocumentReference []NoticeDocumentReference `xml:"NoticeDocumentReference,omitempty"`
|
|
UBLExtensions *UBLExtensions `xml:"UBLExtensions,omitempty"`
|
|
}
|
|
|
|
// TenderSubmissionDeadlinePeriod contains tender submission deadline information
|
|
type TenderSubmissionDeadlinePeriod struct {
|
|
XMLName xml.Name `xml:"TenderSubmissionDeadlinePeriod"`
|
|
EndDate string `xml:"EndDate"`
|
|
EndTime string `xml:"EndTime,omitempty"`
|
|
}
|
|
|
|
// OpenTenderEvent contains open tender event information
|
|
type OpenTenderEvent struct {
|
|
XMLName xml.Name `xml:"OpenTenderEvent"`
|
|
OccurrenceDate string `xml:"OccurrenceDate,omitempty"`
|
|
OccurrenceTime string `xml:"OccurrenceTime,omitempty"`
|
|
Description string `xml:"Description,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
OccurenceLocation *OccurenceLocation `xml:"OccurenceLocation,omitempty"`
|
|
}
|
|
|
|
// OccurenceLocation contains occurrence location information
|
|
type OccurenceLocation struct {
|
|
XMLName xml.Name `xml:"OccurenceLocation"`
|
|
Description string `xml:"Description,omitempty"`
|
|
LanguageID string `xml:"languageID,attr,omitempty"`
|
|
}
|
|
|
|
// AuctionTerms contains auction terms information
|
|
type AuctionTerms struct {
|
|
XMLName xml.Name `xml:"AuctionTerms"`
|
|
AuctionConstraintIndicator string `xml:"AuctionConstraintIndicator,omitempty"`
|
|
}
|
|
|
|
// ContractingSystem contains contracting system information
|
|
type ContractingSystem struct {
|
|
XMLName xml.Name `xml:"ContractingSystem"`
|
|
ContractingSystemTypeCode string `xml:"ContractingSystemTypeCode,omitempty"`
|
|
}
|
|
|
|
// ProcurementProject contains procurement project information
|
|
type ProcurementProject struct {
|
|
XMLName xml.Name `xml:"ProcurementProject"`
|
|
ID string `xml:"ID"`
|
|
Name string `xml:"Name"`
|
|
Description string `xml:"Description"`
|
|
ProcurementTypeCode string `xml:"ProcurementTypeCode"`
|
|
SMESuitableIndicator string `xml:"SMESuitableIndicator,omitempty"`
|
|
Note string `xml:"Note,omitempty"`
|
|
|
|
RequestedTenderTotal *RequestedTenderTotal `xml:"RequestedTenderTotal,omitempty"`
|
|
MainCommodityClassification *MainCommodityClassification `xml:"MainCommodityClassification,omitempty"`
|
|
AdditionalCommodityClassification []AdditionalCommodityClassification `xml:"AdditionalCommodityClassification,omitempty"`
|
|
ProcurementAdditionalType *ProcurementAdditionalType `xml:"ProcurementAdditionalType,omitempty"`
|
|
RealizedLocation *RealizedLocation `xml:"RealizedLocation,omitempty"`
|
|
PlannedPeriod *PlannedPeriod `xml:"PlannedPeriod,omitempty"`
|
|
ContractExtension *ContractExtension `xml:"ContractExtension,omitempty"`
|
|
}
|
|
|
|
// ProcurementAdditionalType contains additional procurement type information
|
|
type ProcurementAdditionalType struct {
|
|
XMLName xml.Name `xml:"ProcurementAdditionalType"`
|
|
ProcurementTypeCode string `xml:"ProcurementTypeCode,omitempty"`
|
|
}
|
|
|
|
// ContractExtension contains contract extension information
|
|
type ContractExtension struct {
|
|
XMLName xml.Name `xml:"ContractExtension"`
|
|
MaximumNumberNumeric string `xml:"MaximumNumberNumeric,omitempty"`
|
|
}
|
|
|
|
// ProcessJustification contains process justification
|
|
type ProcessJustification struct {
|
|
XMLName xml.Name `xml:"ProcessJustification"`
|
|
ProcessReasonCode string `xml:"ProcessReasonCode"`
|
|
}
|
|
|
|
// RequestedTenderTotal contains tender total information
|
|
type RequestedTenderTotal struct {
|
|
XMLName xml.Name `xml:"RequestedTenderTotal"`
|
|
EstimatedOverallContractAmount CurrencyText `xml:"EstimatedOverallContractAmount"`
|
|
}
|
|
|
|
// CurrencyText represents text with currency attribute
|
|
type CurrencyText struct {
|
|
CurrencyID string `xml:"currencyID,attr,omitempty"`
|
|
Text string `xml:",chardata"`
|
|
}
|
|
|
|
// MainCommodityClassification contains main commodity classification
|
|
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
|
|
type AdditionalCommodityClassification struct {
|
|
XMLName xml.Name `xml:"AdditionalCommodityClassification"`
|
|
ItemClassificationCode string `xml:"ItemClassificationCode"`
|
|
}
|
|
|
|
// RealizedLocation contains location information
|
|
type RealizedLocation struct {
|
|
XMLName xml.Name `xml:"RealizedLocation"`
|
|
Description string `xml:"Description,omitempty"`
|
|
Address *Address `xml:"Address,omitempty"`
|
|
}
|
|
|
|
// Address contains address information (different from PostalAddress)
|
|
type Address struct {
|
|
XMLName xml.Name `xml:"Address"`
|
|
StreetName string `xml:"StreetName,omitempty"`
|
|
AdditionalStreetName string `xml:"AdditionalStreetName,omitempty"`
|
|
CityName string `xml:"CityName,omitempty"`
|
|
PostalZone string `xml:"PostalZone,omitempty"`
|
|
CountrySubentityCode string `xml:"CountrySubentityCode,omitempty"`
|
|
Region string `xml:"Region,omitempty"`
|
|
Country *Country `xml:"Country,omitempty"`
|
|
}
|
|
|
|
// PlannedPeriod contains planned period information
|
|
type PlannedPeriod struct {
|
|
XMLName xml.Name `xml:"PlannedPeriod"`
|
|
StartDate string `xml:"StartDate,omitempty"`
|
|
EndDate string `xml:"EndDate,omitempty"`
|
|
DurationMeasure *DurationMeasure `xml:"DurationMeasure,omitempty"`
|
|
}
|
|
|
|
// DurationMeasure contains duration with unit information
|
|
type DurationMeasure struct {
|
|
XMLName xml.Name `xml:"DurationMeasure"`
|
|
UnitCode string `xml:"unitCode,attr,omitempty"`
|
|
Text string `xml:",chardata"`
|
|
}
|
|
|
|
// ProcurementProjectLot contains lot information
|
|
type ProcurementProjectLot struct {
|
|
XMLName xml.Name `xml:"ProcurementProjectLot"`
|
|
ID string `xml:"ID"`
|
|
TenderingTerms *TenderingTerms `xml:"TenderingTerms,omitempty"`
|
|
TenderingProcess *TenderingProcess `xml:"TenderingProcess,omitempty"`
|
|
ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
|
|
}
|
|
|
|
// Validate validates the ContractNotice structure
|
|
func (cn ContractNotice) Validate() error {
|
|
if cn.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
|
|
// Validate date format - TED XML uses ISO 8601 format with timezone
|
|
validFormats := []string{
|
|
"2006-01-02+07:00",
|
|
"2006-01-02-07:00",
|
|
"2006-01-02T15:04:05+07:00",
|
|
"2006-01-02T15:04:05-07:00",
|
|
"2006-01-02T15:04:05Z",
|
|
"2006-01-02Z",
|
|
"2006-01-02",
|
|
time.RFC3339,
|
|
time.RFC3339Nano,
|
|
}
|
|
|
|
var validDate bool
|
|
for _, format := range validFormats {
|
|
if _, err := time.Parse(format, cn.IssueDate); err == nil {
|
|
validDate = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !validDate {
|
|
return fmt.Errorf("invalid issue date format: %s (expected ISO 8601 format)", cn.IssueDate)
|
|
}
|
|
|
|
// Validate language code if provided (should be 3-letter ISO code)
|
|
if cn.NoticeLanguageCode != "" && len(cn.NoticeLanguageCode) != 3 {
|
|
return fmt.Errorf("invalid notice language code: %s (expected 3-letter ISO code)", cn.NoticeLanguageCode)
|
|
}
|
|
|
|
// Validate tender submission deadline format if present
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().TenderingProcess != nil &&
|
|
cn.firstLot().TenderingProcess.TenderSubmissionDeadlinePeriod != nil {
|
|
|
|
deadline := cn.firstLot().TenderingProcess.TenderSubmissionDeadlinePeriod.EndDate
|
|
if deadline != "" {
|
|
var validDeadline bool
|
|
for _, format := range validFormats {
|
|
if _, err := time.Parse(format, deadline); err == nil {
|
|
validDeadline = true
|
|
break
|
|
}
|
|
}
|
|
if !validDeadline {
|
|
return fmt.Errorf("invalid tender submission deadline format: %s (expected ISO 8601 format)", deadline)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validate currency code if provided in budget
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().ProcurementProject != nil &&
|
|
cn.firstLot().ProcurementProject.RequestedTenderTotal != nil {
|
|
|
|
currency := cn.firstLot().ProcurementProject.RequestedTenderTotal.EstimatedOverallContractAmount.CurrencyID
|
|
if currency != "" && len(currency) != 3 {
|
|
return fmt.Errorf("invalid currency code: %s (expected 3-letter ISO code)", currency)
|
|
}
|
|
}
|
|
|
|
// Validate duration unit code if provided
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().ProcurementProject != nil &&
|
|
cn.firstLot().ProcurementProject.PlannedPeriod != nil &&
|
|
cn.firstLot().ProcurementProject.PlannedPeriod.DurationMeasure != nil {
|
|
|
|
unitCode := cn.firstLot().ProcurementProject.PlannedPeriod.DurationMeasure.UnitCode
|
|
if unitCode != "" {
|
|
validUnits := map[string]bool{
|
|
"MONTH": true,
|
|
"DAY": true,
|
|
"WEEK": true,
|
|
"YEAR": true,
|
|
}
|
|
if !validUnits[unitCode] {
|
|
return fmt.Errorf("invalid duration unit code: %s (expected MONTH, DAY, WEEK, or YEAR)", unitCode)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetID returns the contract notice ID
|
|
func (cn ContractNotice) GetID() string {
|
|
return cn.ID
|
|
}
|
|
|
|
// GetNoticeType returns the notice type code (BT-02, cbc:NoticeTypeCode text).
|
|
func (cn ContractNotice) GetNoticeType() string {
|
|
return strings.TrimSpace(cn.NoticeTypeCode.Text)
|
|
}
|
|
|
|
// GetNoticeFormType returns the form type from listName on cbc:NoticeTypeCode (BT-03), e.g. "competition".
|
|
func (cn ContractNotice) GetNoticeFormType() string {
|
|
return strings.TrimSpace(cn.NoticeTypeCode.ListName)
|
|
}
|
|
|
|
// GetLanguage returns the notice language
|
|
func (cn ContractNotice) GetLanguage() string {
|
|
return cn.NoticeLanguageCode
|
|
}
|
|
|
|
// GetPublicationInfo returns publication information if available
|
|
func (cn ContractNotice) GetPublicationInfo() *Publication {
|
|
if ef := ublEformsExtension(cn.Extensions); ef != nil {
|
|
return ef.Publication
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetOrganizations returns organizations from extensions
|
|
func (cn ContractNotice) GetOrganizations() *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 ef := ublEformsExtension(cn.Extensions); ef != nil && ef.NoticeSubType != nil {
|
|
return ef.NoticeSubType.SubTypeCode
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetNoticePublicationID returns the notice publication ID from extensions
|
|
func (cn ContractNotice) GetNoticePublicationID() string {
|
|
pub := cn.GetPublicationInfo()
|
|
if pub != nil {
|
|
return pub.NoticePublicationID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetOJSID returns the OJS gazette ID from extensions
|
|
func (cn ContractNotice) GetOJSID() string {
|
|
pub := cn.GetPublicationInfo()
|
|
if pub != nil {
|
|
return pub.GazetteID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetPublicationDate returns the publication date from extensions
|
|
func (cn ContractNotice) GetPublicationDate() string {
|
|
pub := cn.GetPublicationInfo()
|
|
if pub != nil {
|
|
return pub.PublicationDate
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetOrganizationByID returns an organization by its ID
|
|
func (cn ContractNotice) GetOrganizationByID(orgID string) *Organization {
|
|
orgs := cn.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 (cn ContractNotice) GetBuyerID() string {
|
|
if cn.ContractingParty != nil &&
|
|
cn.ContractingParty.Party != nil &&
|
|
cn.ContractingParty.Party.PartyIdentification != nil {
|
|
return cn.ContractingParty.Party.PartyIdentification.ID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetReviewOrganizationID returns the review organization ID from appeal terms
|
|
func (cn ContractNotice) GetReviewOrganizationID() string {
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().TenderingTerms != nil &&
|
|
cn.firstLot().TenderingTerms.AppealTerms != nil &&
|
|
cn.firstLot().TenderingTerms.AppealTerms.AppealReceiverParty != nil &&
|
|
cn.firstLot().TenderingTerms.AppealTerms.AppealReceiverParty.PartyIdentification != nil {
|
|
return cn.firstLot().TenderingTerms.AppealTerms.AppealReceiverParty.PartyIdentification.ID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetProcedureCode returns the type of procedure
|
|
func (cn ContractNotice) GetProcedureCode() string {
|
|
if cn.TenderingProcess != nil {
|
|
return cn.TenderingProcess.ProcedureCode
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetProcurementTitle returns the notice-level procurement project title
|
|
func (cn ContractNotice) GetProcurementTitle() string {
|
|
if cn.ProcurementProject != nil && strings.TrimSpace(cn.ProcurementProject.Name) != "" {
|
|
return cn.ProcurementProject.Name
|
|
}
|
|
if cn.firstLot() != nil && cn.firstLot().ProcurementProject != nil {
|
|
return cn.firstLot().ProcurementProject.Name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetProcurementDescription returns the notice-level procurement project description
|
|
func (cn ContractNotice) GetProcurementDescription() string {
|
|
if cn.ProcurementProject != nil && strings.TrimSpace(cn.ProcurementProject.Description) != "" {
|
|
return cn.ProcurementProject.Description
|
|
}
|
|
if cn.firstLot() != nil && cn.firstLot().ProcurementProject != nil {
|
|
return cn.firstLot().ProcurementProject.Description
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetContractNature returns the main nature of the contract
|
|
func (cn ContractNotice) GetContractNature() string {
|
|
if cn.ProcurementProject != nil {
|
|
return cn.ProcurementProject.ProcurementTypeCode
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetMainClassification returns the main CPV classification code
|
|
func (cn ContractNotice) GetMainClassification() string {
|
|
if cn.ProcurementProject != nil &&
|
|
cn.ProcurementProject.MainCommodityClassification != nil {
|
|
return cn.ProcurementProject.MainCommodityClassification.ItemClassificationCode
|
|
}
|
|
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 &&
|
|
cn.ProcurementProject.RealizedLocation != nil &&
|
|
cn.ProcurementProject.RealizedLocation.Address != nil {
|
|
return cn.ProcurementProject.RealizedLocation.Address.Region
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetLotID returns the procurement lot ID
|
|
func (cn ContractNotice) GetLotID() string {
|
|
if cn.firstLot() != nil {
|
|
return cn.firstLot().ID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetSelectionCriteria returns selection criteria from extensions
|
|
func (cn ContractNotice) GetSelectionCriteria() []SelectionCriteria {
|
|
if ef := ublEformsExtension(cn.Extensions); ef != nil {
|
|
return ef.SelectionCriteria
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetOfficialLanguages returns official languages from tender terms extensions
|
|
func (cn ContractNotice) GetOfficialLanguages() []string {
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().TenderingTerms != nil &&
|
|
len(cn.firstLot().TenderingTerms.CallForTendersDocumentReference) > 0 &&
|
|
cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions != nil &&
|
|
cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension != nil &&
|
|
cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent != nil &&
|
|
cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension != nil &&
|
|
cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages != nil {
|
|
|
|
languages := make([]string, len(cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages.Language))
|
|
for i, lang := range cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages.Language {
|
|
languages[i] = lang.ID
|
|
}
|
|
return languages
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetDocumentURI returns the document URI from call for tenders document reference
|
|
func (cn ContractNotice) GetDocumentURI() string {
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().TenderingTerms != nil &&
|
|
len(cn.firstLot().TenderingTerms.CallForTendersDocumentReference) > 0 &&
|
|
cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].Attachment != nil &&
|
|
cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].Attachment.ExternalReference != nil {
|
|
return cn.firstLot().TenderingTerms.CallForTendersDocumentReference[0].Attachment.ExternalReference.URI
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetAllDocumentURIs returns all document URIs from call for tenders document references
|
|
func (cn ContractNotice) GetAllDocumentURIs() []string {
|
|
var uris []string
|
|
for i := range cn.ProcurementProjectLots {
|
|
lot := &cn.ProcurementProjectLots[i]
|
|
if lot.TenderingTerms == nil {
|
|
continue
|
|
}
|
|
for _, docRef := range lot.TenderingTerms.CallForTendersDocumentReference {
|
|
if docRef.Attachment != nil &&
|
|
docRef.Attachment.ExternalReference != nil &&
|
|
docRef.Attachment.ExternalReference.URI != "" {
|
|
uris = append(uris, docRef.Attachment.ExternalReference.URI)
|
|
}
|
|
}
|
|
}
|
|
return uris
|
|
}
|
|
|
|
// GetTenderDeadline returns the tender submission deadline
|
|
func (cn ContractNotice) GetTenderDeadline() string {
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().TenderingProcess != nil &&
|
|
cn.firstLot().TenderingProcess.TenderSubmissionDeadlinePeriod != nil {
|
|
return cn.firstLot().TenderingProcess.TenderSubmissionDeadlinePeriod.EndDate
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetBudget returns the estimated contract amount and currency
|
|
func (cn ContractNotice) GetBudget() (amount string, currency string) {
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().ProcurementProject != nil &&
|
|
cn.firstLot().ProcurementProject.RequestedTenderTotal != nil {
|
|
|
|
contractAmount := cn.firstLot().ProcurementProject.RequestedTenderTotal.EstimatedOverallContractAmount
|
|
return contractAmount.Text, contractAmount.CurrencyID
|
|
}
|
|
return "", ""
|
|
}
|
|
|
|
// GetDuration returns the contract duration and unit
|
|
func (cn ContractNotice) GetDuration() (duration string, unit string) {
|
|
if cn.firstLot() != nil &&
|
|
cn.firstLot().ProcurementProject != nil &&
|
|
cn.firstLot().ProcurementProject.PlannedPeriod != nil &&
|
|
cn.firstLot().ProcurementProject.PlannedPeriod.DurationMeasure != nil {
|
|
|
|
durationMeasure := cn.firstLot().ProcurementProject.PlannedPeriod.DurationMeasure
|
|
return durationMeasure.Text, durationMeasure.UnitCode
|
|
}
|
|
return "", ""
|
|
}
|
|
|
|
// ==================== ContractAwardNotice Methods ====================
|
|
|
|
// Validate validates the ContractAwardNotice structure
|
|
func (can ContractAwardNotice) Validate() error {
|
|
if can.ID == "" {
|
|
return fmt.Errorf("contract award notice ID is required")
|
|
}
|
|
|
|
if can.ContractFolderID == "" {
|
|
return fmt.Errorf("contract folder ID is required")
|
|
}
|
|
|
|
if can.IssueDate == "" {
|
|
return fmt.Errorf("issue date is required")
|
|
}
|
|
|
|
// Validate date format - TED XML uses ISO 8601 format with timezone
|
|
validFormats := []string{
|
|
"2006-01-02+07:00",
|
|
"2006-01-02-07:00",
|
|
"2006-01-02T15:04:05+07:00",
|
|
"2006-01-02T15:04:05-07:00",
|
|
"2006-01-02T15:04:05Z",
|
|
"2006-01-02Z",
|
|
"2006-01-02",
|
|
time.RFC3339,
|
|
time.RFC3339Nano,
|
|
}
|
|
|
|
var validDate bool
|
|
for _, format := range validFormats {
|
|
if _, err := time.Parse(format, can.IssueDate); err == nil {
|
|
validDate = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !validDate {
|
|
return fmt.Errorf("invalid issue date format: %s (expected ISO 8601 format)", can.IssueDate)
|
|
}
|
|
|
|
// Validate language code if provided (should be 3-letter ISO code)
|
|
if can.NoticeLanguageCode != "" && len(can.NoticeLanguageCode) != 3 {
|
|
return fmt.Errorf("invalid notice language code: %s (expected 3-letter ISO code)", can.NoticeLanguageCode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetID returns the contract award notice ID
|
|
func (can ContractAwardNotice) GetID() string {
|
|
return can.ID
|
|
}
|
|
|
|
// GetNoticeType returns the notice type code (BT-02).
|
|
func (can ContractAwardNotice) GetNoticeType() string {
|
|
return strings.TrimSpace(can.NoticeTypeCode.Text)
|
|
}
|
|
|
|
// GetNoticeFormType returns the form type from listName (BT-03).
|
|
func (can ContractAwardNotice) GetNoticeFormType() string {
|
|
return strings.TrimSpace(can.NoticeTypeCode.ListName)
|
|
}
|
|
|
|
// GetLanguage returns the notice language
|
|
func (can ContractAwardNotice) GetLanguage() string {
|
|
return can.NoticeLanguageCode
|
|
}
|
|
|
|
// GetPublicationInfo returns publication information if available
|
|
func (can ContractAwardNotice) GetPublicationInfo() *Publication {
|
|
if can.Extensions != nil &&
|
|
can.Extensions.UBLExtension != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
|
|
return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.Publication
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetOrganizations returns organizations from extensions
|
|
func (can ContractAwardNotice) GetOrganizations() *Organizations {
|
|
if can.Extensions != nil &&
|
|
can.Extensions.UBLExtension != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
|
|
return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.Organizations
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetNoticeResult returns notice result from extensions
|
|
func (can ContractAwardNotice) GetNoticeResult() *NoticeResult {
|
|
if can.Extensions != nil &&
|
|
can.Extensions.UBLExtension != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
|
|
return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeResult
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetNoticeSubType returns the notice subtype code from extensions
|
|
func (can ContractAwardNotice) GetNoticeSubType() string {
|
|
if can.Extensions != nil &&
|
|
can.Extensions.UBLExtension != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil &&
|
|
can.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType != nil {
|
|
return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType.SubTypeCode
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetNoticePublicationID returns the notice publication ID from extensions
|
|
func (can ContractAwardNotice) GetNoticePublicationID() string {
|
|
pub := can.GetPublicationInfo()
|
|
if pub != nil {
|
|
return pub.NoticePublicationID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetOJSID returns the OJS gazette ID from extensions
|
|
func (can ContractAwardNotice) GetOJSID() string {
|
|
pub := can.GetPublicationInfo()
|
|
if pub != nil {
|
|
return pub.GazetteID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetPublicationDate returns the publication date from extensions
|
|
func (can ContractAwardNotice) GetPublicationDate() string {
|
|
pub := can.GetPublicationInfo()
|
|
if pub != nil {
|
|
return pub.PublicationDate
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetBuyerID returns the buyer organization ID from contracting party
|
|
func (can ContractAwardNotice) GetBuyerID() string {
|
|
if can.ContractingParty != nil &&
|
|
can.ContractingParty.Party != nil &&
|
|
can.ContractingParty.Party.PartyIdentification != nil {
|
|
return can.ContractingParty.Party.PartyIdentification.ID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetProcedureCode returns the type of procedure
|
|
func (can ContractAwardNotice) GetProcedureCode() string {
|
|
if can.TenderingProcess != nil {
|
|
return can.TenderingProcess.ProcedureCode
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetProcurementTitle returns the procurement project title
|
|
func (can ContractAwardNotice) GetProcurementTitle() string {
|
|
if can.ProcurementProject != nil && strings.TrimSpace(can.ProcurementProject.Name) != "" {
|
|
return can.ProcurementProject.Name
|
|
}
|
|
if lot := can.firstAwardLot(); lot != nil && lot.ProcurementProject != nil {
|
|
return lot.ProcurementProject.Name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetProcurementDescription returns the procurement project description
|
|
func (can ContractAwardNotice) GetProcurementDescription() string {
|
|
if can.ProcurementProject != nil && strings.TrimSpace(can.ProcurementProject.Description) != "" {
|
|
return can.ProcurementProject.Description
|
|
}
|
|
if lot := can.firstAwardLot(); lot != nil && lot.ProcurementProject != nil {
|
|
return lot.ProcurementProject.Description
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetContractNature returns the main nature of the contract
|
|
func (can ContractAwardNotice) GetContractNature() string {
|
|
if can.ProcurementProject != nil && strings.TrimSpace(can.ProcurementProject.ProcurementTypeCode) != "" {
|
|
return can.ProcurementProject.ProcurementTypeCode
|
|
}
|
|
if lot := can.firstAwardLot(); lot != nil && lot.ProcurementProject != nil {
|
|
return lot.ProcurementProject.ProcurementTypeCode
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetMainClassification returns the main CPV classification code
|
|
func (can ContractAwardNotice) GetMainClassification() string {
|
|
if can.ProcurementProject != nil &&
|
|
can.ProcurementProject.MainCommodityClassification != nil {
|
|
return can.ProcurementProject.MainCommodityClassification.ItemClassificationCode
|
|
}
|
|
if lot := can.firstAwardLot(); 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 (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()
|
|
if noticeResult != nil && noticeResult.TotalAmount != nil {
|
|
return noticeResult.TotalAmount.Text, noticeResult.TotalAmount.CurrencyID
|
|
}
|
|
return "", ""
|
|
}
|
|
|
|
// GetAwardDate returns the tender award date
|
|
func (can ContractAwardNotice) GetAwardDate() string {
|
|
if can.TenderResult != nil {
|
|
return can.TenderResult.AwardDate
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetOrganizationByID returns an organization by its ID
|
|
func (can ContractAwardNotice) GetOrganizationByID(orgID string) *Organization {
|
|
orgs := can.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
|
|
}
|
|
|
|
// GetWinningTenderPartyID resolves the tendering party reference for the primary winning bid from NoticeResult.
|
|
func (can ContractAwardNotice) GetWinningTenderPartyID() string {
|
|
nr := can.GetNoticeResult()
|
|
if nr == nil {
|
|
return ""
|
|
}
|
|
for _, lr := range nr.LotResult {
|
|
winner := pickWinningLotTender(lr.LotTender)
|
|
if winner != nil && winner.TenderingParty != nil && winner.TenderingParty.ID != "" {
|
|
return winner.TenderingParty.ID
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetWinningTenderOrganization resolves the winning tenderer organization from NoticeResult via Organizations.
|
|
func (can ContractAwardNotice) GetWinningTenderOrganization() *Organization {
|
|
id := can.GetWinningTenderPartyID()
|
|
if id == "" {
|
|
return nil
|
|
}
|
|
return can.GetOrganizationByID(id)
|
|
}
|