Enhance tender estimated value resolution and add unit tests
- Updated the `ResolvedEstimatedValueAndCurrency` method to aggregate procurement lot values when the tender-level estimated value is not set, improving accuracy in value retrieval. - Introduced the `AggregateProcurementLotEstimatedValue` function to sum estimated values from procurement lots and return the first found currency. - Modified the `ToResponseWithLanguage` method to utilize the new estimated value resolution logic. - Added unit tests for the new functionality, ensuring correct behavior for various scenarios in the `entity_test.go` and `budget_test.go` files. This update improves the handling of estimated values in tenders, enhancing the overall reliability of the tender management system.
This commit is contained in:
@@ -305,20 +305,55 @@ func (t *Tender) GetMainOrganization() *Organization {
|
||||
|
||||
// HasEstimatedValue returns true if the tender has an estimated value
|
||||
func (t *Tender) HasEstimatedValue() bool {
|
||||
return t.EstimatedValue > 0
|
||||
value, _ := t.ResolvedEstimatedValueAndCurrency()
|
||||
return value > 0
|
||||
}
|
||||
|
||||
// AggregateProcurementLotEstimatedValue sums lot-level estimated values and returns the first lot currency found.
|
||||
func AggregateProcurementLotEstimatedValue(lots []ProcurementLot) (value float64, currency string) {
|
||||
for _, lot := range lots {
|
||||
if lot.EstimatedValue <= 0 {
|
||||
continue
|
||||
}
|
||||
value += lot.EstimatedValue
|
||||
if currency == "" {
|
||||
currency = strings.TrimSpace(lot.Currency)
|
||||
}
|
||||
}
|
||||
return value, currency
|
||||
}
|
||||
|
||||
// ResolvedEstimatedValueAndCurrency returns the tender-level estimated value when set,
|
||||
// otherwise aggregates procurement lot values for API and display use.
|
||||
func (t *Tender) ResolvedEstimatedValueAndCurrency() (float64, string) {
|
||||
if t == nil {
|
||||
return 0, ""
|
||||
}
|
||||
if t.EstimatedValue > 0 {
|
||||
return t.EstimatedValue, strings.TrimSpace(t.Currency)
|
||||
}
|
||||
value, currency := AggregateProcurementLotEstimatedValue(t.ProcurementLots)
|
||||
if value > 0 {
|
||||
if currency == "" {
|
||||
currency = strings.TrimSpace(t.Currency)
|
||||
}
|
||||
return value, currency
|
||||
}
|
||||
return 0, strings.TrimSpace(t.Currency)
|
||||
}
|
||||
|
||||
// GetFormattedEstimatedValue returns formatted estimated value with currency
|
||||
func (t *Tender) GetFormattedEstimatedValue() string {
|
||||
if !t.HasEstimatedValue() {
|
||||
value, currency := t.ResolvedEstimatedValueAndCurrency()
|
||||
if value <= 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if t.Currency != "" {
|
||||
return fmt.Sprintf("%.2f %s", t.EstimatedValue, t.Currency)
|
||||
if currency != "" {
|
||||
return fmt.Sprintf("%.2f %s", value, currency)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%.2f", t.EstimatedValue)
|
||||
return fmt.Sprintf("%.2f", value)
|
||||
}
|
||||
|
||||
// UpdateStatus updates the tender status and updated timestamp
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package tender
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAggregateProcurementLotEstimatedValue(t *testing.T) {
|
||||
value, currency := AggregateProcurementLotEstimatedValue([]ProcurementLot{
|
||||
{EstimatedValue: 100000, Currency: "EUR"},
|
||||
{EstimatedValue: 250000, Currency: "EUR"},
|
||||
})
|
||||
if value != 350000 {
|
||||
t.Fatalf("expected total 350000, got %v", value)
|
||||
}
|
||||
if currency != "EUR" {
|
||||
t.Fatalf("expected currency EUR, got %q", currency)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvedEstimatedValueAndCurrencyUsesLotsWhenTopLevelMissing(t *testing.T) {
|
||||
tender := &Tender{
|
||||
Currency: "EUR",
|
||||
ProcurementLots: []ProcurementLot{
|
||||
{LotID: "LOT-0001", EstimatedValue: 500000, Currency: "EUR"},
|
||||
},
|
||||
}
|
||||
|
||||
value, currency := tender.ResolvedEstimatedValueAndCurrency()
|
||||
if value != 500000 {
|
||||
t.Fatalf("expected 500000, got %v", value)
|
||||
}
|
||||
if currency != "EUR" {
|
||||
t.Fatalf("expected EUR, got %q", currency)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvedEstimatedValueAndCurrencyPrefersTopLevel(t *testing.T) {
|
||||
tender := &Tender{
|
||||
EstimatedValue: 900000,
|
||||
Currency: "USD",
|
||||
ProcurementLots: []ProcurementLot{
|
||||
{EstimatedValue: 100000, Currency: "EUR"},
|
||||
},
|
||||
}
|
||||
|
||||
value, currency := tender.ResolvedEstimatedValueAndCurrency()
|
||||
if value != 900000 {
|
||||
t.Fatalf("expected 900000, got %v", value)
|
||||
}
|
||||
if currency != "USD" {
|
||||
t.Fatalf("expected USD, got %q", currency)
|
||||
}
|
||||
}
|
||||
@@ -277,6 +277,8 @@ func (t *Tender) ToResponseWithLanguage(language string) *TenderResponse {
|
||||
documentURL = strings.TrimSpace(t.TenderURL)
|
||||
}
|
||||
|
||||
estimatedValue, currency := t.ResolvedEstimatedValueAndCurrency()
|
||||
|
||||
response := &TenderResponse{
|
||||
ID: t.ID.Hex(),
|
||||
NoticePublicationID: t.NoticePublicationID,
|
||||
@@ -307,8 +309,8 @@ func (t *Tender) ToResponseWithLanguage(language string) *TenderResponse {
|
||||
MainClassificationDescription: mainDesc,
|
||||
MainClassificationDisplay: classificationDisplay(mainCode, mainDesc),
|
||||
AdditionalClassifications: append([]string(nil), t.AdditionalClassifications...),
|
||||
EstimatedValue: t.EstimatedValue,
|
||||
Currency: strings.TrimSpace(t.Currency),
|
||||
EstimatedValue: estimatedValue,
|
||||
Currency: currency,
|
||||
EstimatedValueVATBasis: vatBasisUnspecified,
|
||||
|
||||
Duration: t.Duration,
|
||||
|
||||
Reference in New Issue
Block a user