package findATender import ( "encoding/json" "slices" "strings" "git.avsdev.uk/Go/job-search/internal/findATender/ocds" "git.avsdev.uk/Go/job-search/internal/types" ) func ocdsGetBuyerId(release *ocds.Release) string { if release.Buyer != nil { return string(release.Buyer.ID) } return "" } func ocdsGetBuyerName(release *ocds.Release) string { if release.Buyer != nil { return release.Buyer.Name } return "" } func ocdsConvertClassification( classif *ocds.Classification, ) types.ClassificationCode { return types.ClassificationCode{ IsCPV: strings.Compare(classif.Scheme, "CPV") == 0, Code: string(classif.ID), Classification: classif.Description, } } func ocdsGetClassifications(release *ocds.Release) []types.ClassificationCode { classifications := make([]types.ClassificationCode, 0) if release.Tender == nil { return classifications } add := func(classif *ocds.Classification) { newClassif := ocdsConvertClassification(classif) found := slices.ContainsFunc( classifications, func(r types.ClassificationCode) bool { return r.Code == newClassif.Code }, ) if !found { classifications = append(classifications, newClassif) } } if release.Tender.Classification != nil { add(release.Tender.Classification) } for _, val := range release.Tender.Items { if val.Classification != nil { add(val.Classification) } for _, classif := range val.AdditionalClassifications { add(&classif) } } return classifications } func ocdsIsSMESuitable(release *ocds.Release) bool { if release.Tender == nil { return false } if len(release.Tender.Lots) == 0 { return false } for _, lot := range release.Tender.Lots { if lot.Suitability != nil { if lot.Suitability.SME != nil && *lot.Suitability.SME { return true } } } return false } func ocdsIsVCSESuitable(release *ocds.Release) bool { if release.Tender == nil { return false } if len(release.Tender.Lots) == 0 { return false } for _, lot := range release.Tender.Lots { if lot.Suitability != nil { if lot.Suitability.Vcse != nil && *lot.Suitability.Vcse { return true } } } return false } func ocdsRelease(release *ocds.Release) types.OpportunityRelease { tags := make([]types.OpportunityReleaseTag, 0) for _, val := range release.Tag { tags = append(tags, types.OpportunityReleaseTag{ UUID: release.OCID, ReleaseID: release.ID, Tag: val, }) } rel := types.OpportunityRelease{ UUID: release.OCID, ReleaseID: release.ID, Tags: tags, ReleaseDate: release.Date, } reencoded, err := json.Marshal(release) if err == nil { rel.JSON = string(reencoded) } return rel } func convertOne(release *ocds.Release) *types.Opportunity { t := &types.Opportunity{ UUID: release.OCID, UUIDType: "ocid", BuyerId: ocdsGetBuyerId(release), BuyerName: ocdsGetBuyerName(release), } if release.Tender != nil { t.Title = release.Tender.Title t.Status = release.Tender.Status t.Description = release.Tender.Description t.Classifications = ocdsGetClassifications(release) t.MainCategory = release.Tender.MainProcurementCategory t.ProcurementMethod = release.Tender.ProcurementMethod t.SMESuitable = ocdsIsSMESuitable(release) t.VCSESuitable = ocdsIsVCSESuitable(release) if release.Tender.TenderPeriod != nil { t.StartDate = release.Tender.TenderPeriod.StartDate t.EndDate = release.Tender.TenderPeriod.EndDate } if release.Tender.Value != nil && release.Tender.Value.Amount != nil { t.GrossValue = *release.Tender.Value.Amount } t.HasDocuments = len(release.Tender.Documents) > 0 t.MultiLot = len(release.Tender.Lots) > 1 } t.LatestReleaseDate = release.Date t.Releases = append(t.Releases, ocdsRelease(release)) return t } // Convert groups releases by ocid into opportunities, in the order each ocid // first appears. Each opportunity is built from its latest release (by date, // or the later one in releases on a tie) and lists all of its releases oldest // first. func Convert(releases []ocds.Release) []*types.Opportunity { var order []string byOCID := make(map[string][]*ocds.Release) for idx := range releases { release := &releases[idx] if _, found := byOCID[release.OCID]; !found { order = append(order, release.OCID) } byOCID[release.OCID] = append(byOCID[release.OCID], release) } opportunities := make([]*types.Opportunity, 0, len(order)) for _, ocid := range order { group := byOCID[ocid] slices.SortStableFunc(group, func(a, b *ocds.Release) int { return a.Date.Compare(b.Date) }) opportunity := convertOne(group[len(group)-1]) opportunity.Releases = make([]types.OpportunityRelease, 0, len(group)) for _, release := range group { opportunity.Releases = append(opportunity.Releases, ocdsRelease(release)) } opportunities = append(opportunities, opportunity) } return opportunities }