Enhance procurement lot estimated value aggregation and add unit tests

- Updated the `AggregateProcurementLotEstimatedValue` function to reject mixed currencies and allow empty lot currencies, ensuring accurate aggregation of estimated values.
- Introduced new unit tests in `entity_test.go` to validate the behavior of the aggregation function under various scenarios, including mixed currencies and empty lot currencies.
- Refactored budget calculation in `budget_test.go` to utilize the new aggregation logic, improving consistency in budget retrieval.

This update improves the handling of estimated values in procurement lots, enhancing the reliability of the tender management system.
This commit is contained in:
Mazyar
2026-06-21 09:41:33 +03:30
parent a04b3fe1ec
commit ee5414bc10
6 changed files with 124 additions and 16 deletions
+41
View File
@@ -0,0 +1,41 @@
package ted
import "strings"
type valuedAmount struct {
value float64
currency string
}
// aggregateSameCurrencyAmounts sums values only when every non-empty currency matches.
// Lots with an empty currency are included; conflicting currencies yield zero.
func aggregateSameCurrencyAmounts(amounts []valuedAmount) (total float64, currency string) {
var refCurrency string
for _, item := range amounts {
if item.value <= 0 {
continue
}
c := strings.TrimSpace(item.currency)
if c == "" {
continue
}
if refCurrency == "" {
refCurrency = c
continue
}
if c != refCurrency {
return 0, ""
}
}
for _, item := range amounts {
if item.value <= 0 {
continue
}
total += item.value
}
if total <= 0 {
return 0, ""
}
return total, refCurrency
}
+26
View File
@@ -56,3 +56,29 @@ func TestContractNoticeGetBudgetSumsAllLots(t *testing.T) {
t.Fatalf("expected EUR, got %q", currency)
}
}
func TestContractNoticeGetBudgetRejectsMixedCurrencies(t *testing.T) {
cn := ContractNotice{
ProcurementProjectLots: []ProcurementProjectLot{
{
ProcurementProject: &ProcurementProject{
RequestedTenderTotal: &RequestedTenderTotal{
EstimatedOverallContractAmount: CurrencyText{CurrencyID: "EUR", Text: "100000"},
},
},
},
{
ProcurementProject: &ProcurementProject{
RequestedTenderTotal: &RequestedTenderTotal{
EstimatedOverallContractAmount: CurrencyText{CurrencyID: "USD", Text: "250000"},
},
},
},
},
}
amount, currency := cn.GetBudget()
if amount != "" || currency != "" {
t.Fatalf("expected no budget for mixed currencies, got amount=%q currency=%q", amount, currency)
}
}
+6 -6
View File
@@ -671,17 +671,17 @@ func backfillNoticeEstimatedValueFromLots(t *notice.Notice) {
if t == nil || t.EstimatedValue > 0 {
return
}
var total float64
var currency string
amounts := make([]valuedAmount, 0, len(t.ProcurementLots))
for _, lot := range t.ProcurementLots {
if lot.EstimatedValue <= 0 {
continue
}
total += lot.EstimatedValue
if currency == "" {
currency = strings.TrimSpace(lot.Currency)
}
amounts = append(amounts, valuedAmount{
value: lot.EstimatedValue,
currency: lot.Currency,
})
}
total, currency := aggregateSameCurrencyAmounts(amounts)
if total <= 0 {
return
}
+4 -5
View File
@@ -2003,7 +2003,7 @@ func (cn ContractNotice) GetBudget() (amount string, currency string) {
}
func budgetFromProcurementLots(lots []ProcurementProjectLot) (amount string, currency string) {
var total float64
amounts := make([]valuedAmount, 0, len(lots))
for i := range lots {
pp := lots[i].ProcurementProject
if pp == nil || pp.RequestedTenderTotal == nil {
@@ -2017,11 +2017,10 @@ func budgetFromProcurementLots(lots []ProcurementProjectLot) (amount string, cur
if !ok || value <= 0 {
continue
}
total += value
if currency == "" {
currency = lotCurrency
}
amounts = append(amounts, valuedAmount{value: value, currency: lotCurrency})
}
total, currency := aggregateSameCurrencyAmounts(amounts)
if total <= 0 {
return "", ""
}