added missing tender data to response
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
package document_scraper
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tm/internal/tender"
|
||||
)
|
||||
|
||||
const (
|
||||
enrichmentMainCPVDescription = "main_classification_description"
|
||||
vatBasisUnspecified = "unspecified"
|
||||
)
|
||||
|
||||
// BuildDocumentScraperTenderResponse maps a stored tender to the scraper API contract.
|
||||
func BuildDocumentScraperTenderResponse(t *tender.Tender) *DocumentScraperTenderResponse {
|
||||
if t == nil {
|
||||
return &DocumentScraperTenderResponse{
|
||||
Lots: []DocumentScraperLotResponse{},
|
||||
Winners: []DocumentScraperWinnerResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
documentURL := strings.TrimSpace(t.DocumentURI)
|
||||
if documentURL == "" {
|
||||
documentURL = strings.TrimSpace(t.TenderURL)
|
||||
}
|
||||
|
||||
mainDesc := firstNonEmpty(
|
||||
strings.TrimSpace(t.ProcessingMetadata.EnrichmentData[enrichmentMainCPVDescription]),
|
||||
strings.TrimSpace(t.MainClassificationDescription),
|
||||
)
|
||||
|
||||
resp := &DocumentScraperTenderResponse{
|
||||
ContractFolderID: t.ContractFolderID,
|
||||
NoticePublicationID: t.NoticePublicationID,
|
||||
DocumentURL: documentURL,
|
||||
Title: t.Title,
|
||||
Description: t.Description,
|
||||
NoticeIdentifier: strings.TrimSpace(t.NoticeIdentifier),
|
||||
NoticeVersion: strings.TrimSpace(t.NoticeVersion),
|
||||
FormType: strings.TrimSpace(t.FormType),
|
||||
NoticeType: strings.TrimSpace(t.NoticeTypeCode),
|
||||
NoticeSubtype: strings.TrimSpace(t.NoticeSubTypeCode),
|
||||
PublicationDate: t.PublicationDate,
|
||||
NoticeDispatchDateWithTimezone: formatNoticeDispatchRFC3339(t),
|
||||
ProcurementTypeCode: strings.TrimSpace(t.ProcurementTypeCode),
|
||||
MainClassification: strings.TrimSpace(t.MainClassification),
|
||||
MainClassificationDescription: mainDesc,
|
||||
MainClassificationDisplay: classificationDisplay(strings.TrimSpace(t.MainClassification), mainDesc),
|
||||
AdditionalClassifications: append([]string(nil), t.AdditionalClassifications...),
|
||||
EstimatedValue: t.EstimatedValue,
|
||||
EstimatedValueCurrency: strings.TrimSpace(t.Currency),
|
||||
EstimatedValueVATBasis: vatBasisUnspecified,
|
||||
Status: string(t.Status),
|
||||
Buyer: buildBuyer(t),
|
||||
Lots: buildLots(t, mainDesc),
|
||||
Winners: buildWinners(t),
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func formatNoticeDispatchRFC3339(t *tender.Tender) string {
|
||||
sec := t.NoticeDispatchAt
|
||||
if sec == 0 {
|
||||
sec = t.ESenderDispatchAt
|
||||
}
|
||||
if sec == 0 {
|
||||
return ""
|
||||
}
|
||||
return time.Unix(sec, 0).UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func buildBuyer(t *tender.Tender) DocumentScraperBuyerResponse {
|
||||
if t.BuyerOrganization == nil {
|
||||
return DocumentScraperBuyerResponse{}
|
||||
}
|
||||
b := t.BuyerOrganization
|
||||
return DocumentScraperBuyerResponse{
|
||||
BuyerName: strings.TrimSpace(b.Name),
|
||||
BuyerEmail: strings.TrimSpace(b.ContactEmail),
|
||||
BuyerCountry: strings.TrimSpace(b.Address.CountryCode),
|
||||
BuyerRegionNuts: strings.TrimSpace(b.Address.CountrySubentityCode),
|
||||
BuyerCity: strings.TrimSpace(b.Address.CityName),
|
||||
BuyerProfileURL: strings.TrimSpace(firstNonEmpty(t.BuyerProfileURL, b.WebsiteURI)),
|
||||
}
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, v := range values {
|
||||
if s := strings.TrimSpace(v); s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func classificationDisplay(code, description string) string {
|
||||
code = strings.TrimSpace(code)
|
||||
description = strings.TrimSpace(description)
|
||||
if code != "" && description != "" {
|
||||
return code + " - " + description
|
||||
}
|
||||
if code != "" {
|
||||
return code
|
||||
}
|
||||
return description
|
||||
}
|
||||
|
||||
func buildLots(t *tender.Tender, globalMainDesc string) []DocumentScraperLotResponse {
|
||||
if len(t.ProcurementLots) == 0 {
|
||||
return []DocumentScraperLotResponse{}
|
||||
}
|
||||
out := make([]DocumentScraperLotResponse, 0, len(t.ProcurementLots))
|
||||
for _, lot := range t.ProcurementLots {
|
||||
lotCode := strings.TrimSpace(lot.MainClassification)
|
||||
perLotDesc := strings.TrimSpace(lot.MainClassificationDescription)
|
||||
if perLotDesc == "" && lotCode != "" && lotCode == strings.TrimSpace(t.MainClassification) {
|
||||
perLotDesc = globalMainDesc
|
||||
}
|
||||
out = append(out, DocumentScraperLotResponse{
|
||||
LotID: strings.TrimSpace(lot.LotID),
|
||||
LotTitle: strings.TrimSpace(lot.Title),
|
||||
LotDescription: strings.TrimSpace(lot.Description),
|
||||
LotMainNature: strings.TrimSpace(lot.MainNatureOfContract),
|
||||
LotMainClassificationCode: lotCode,
|
||||
LotMainClassificationDescription: perLotDesc,
|
||||
LotMainClassificationDisplay: classificationDisplay(lotCode, perLotDesc),
|
||||
AdditionalClassifications: append([]string(nil), lot.AdditionalClassifications...),
|
||||
LotDuration: strings.TrimSpace(lot.Duration),
|
||||
LotEstimatedValueExclVAT: lot.EstimatedValue,
|
||||
LotEstimatedValueCurrency: strings.TrimSpace(lot.Currency),
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func buildWinners(t *tender.Tender) []DocumentScraperWinnerResponse {
|
||||
if len(t.AwardedEntities) > 0 {
|
||||
out := make([]DocumentScraperWinnerResponse, 0, len(t.AwardedEntities))
|
||||
for _, a := range t.AwardedEntities {
|
||||
w := DocumentScraperWinnerResponse{
|
||||
OfficialName: strings.TrimSpace(a.Name),
|
||||
RegistrationNumber: strings.TrimSpace(a.CompanyID),
|
||||
PostalAddress: strings.TrimSpace(a.Address),
|
||||
Country: strings.TrimSpace(a.Country),
|
||||
LotID: strings.TrimSpace(a.LotID),
|
||||
Town: "",
|
||||
Postcode: "",
|
||||
CountrySubdivisionNuts: "",
|
||||
ContactPoint: "",
|
||||
Email: "",
|
||||
Telephone: "",
|
||||
}
|
||||
if org := orgByID(t, a.OrganizationID); org != nil {
|
||||
mergeWinnerFromOrganization(&w, org)
|
||||
}
|
||||
out = append(out, w)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
if t.WinningTenderer == nil {
|
||||
return []DocumentScraperWinnerResponse{}
|
||||
}
|
||||
w := t.WinningTenderer
|
||||
if strings.TrimSpace(w.Name) == "" {
|
||||
return []DocumentScraperWinnerResponse{}
|
||||
}
|
||||
addr := w.Address
|
||||
return []DocumentScraperWinnerResponse{{
|
||||
OfficialName: strings.TrimSpace(w.Name),
|
||||
RegistrationNumber: strings.TrimSpace(w.CompanyID),
|
||||
PostalAddress: strings.TrimSpace(addr.StreetName),
|
||||
Town: strings.TrimSpace(addr.CityName),
|
||||
Postcode: strings.TrimSpace(addr.PostalZone),
|
||||
CountrySubdivisionNuts: strings.TrimSpace(addr.CountrySubentityCode),
|
||||
Country: strings.TrimSpace(addr.CountryCode),
|
||||
ContactPoint: strings.TrimSpace(w.ContactName),
|
||||
Email: strings.TrimSpace(w.ContactEmail),
|
||||
Telephone: strings.TrimSpace(w.ContactTelephone),
|
||||
}}
|
||||
}
|
||||
|
||||
func orgByID(t *tender.Tender, id string) *tender.Organization {
|
||||
id = strings.TrimSpace(id)
|
||||
if id == "" || t == nil {
|
||||
return nil
|
||||
}
|
||||
for i := range t.Organizations {
|
||||
if strings.TrimSpace(t.Organizations[i].ID) == id {
|
||||
return &t.Organizations[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mergeWinnerFromOrganization(w *DocumentScraperWinnerResponse, org *tender.Organization) {
|
||||
if w == nil || org == nil {
|
||||
return
|
||||
}
|
||||
if w.OfficialName == "" {
|
||||
w.OfficialName = strings.TrimSpace(org.Name)
|
||||
}
|
||||
if w.RegistrationNumber == "" {
|
||||
w.RegistrationNumber = strings.TrimSpace(org.CompanyID)
|
||||
}
|
||||
if w.PostalAddress == "" {
|
||||
w.PostalAddress = strings.TrimSpace(org.Address.StreetName)
|
||||
}
|
||||
if w.Town == "" {
|
||||
w.Town = strings.TrimSpace(org.Address.CityName)
|
||||
}
|
||||
if w.Postcode == "" {
|
||||
w.Postcode = strings.TrimSpace(org.Address.PostalZone)
|
||||
}
|
||||
if w.CountrySubdivisionNuts == "" {
|
||||
w.CountrySubdivisionNuts = strings.TrimSpace(org.Address.CountrySubentityCode)
|
||||
}
|
||||
if w.Country == "" {
|
||||
w.Country = strings.TrimSpace(org.Address.CountryCode)
|
||||
}
|
||||
if w.ContactPoint == "" {
|
||||
w.ContactPoint = strings.TrimSpace(org.ContactName)
|
||||
}
|
||||
if w.Email == "" {
|
||||
w.Email = strings.TrimSpace(org.ContactEmail)
|
||||
}
|
||||
if w.Telephone == "" {
|
||||
w.Telephone = strings.TrimSpace(org.ContactTelephone)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user