Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pkg/common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ type Recommendation struct {
// frontend renders nil as "—" rather than "$0" to avoid misleading users.
// Populated by cloud parsers when the API exposes it; left nil otherwise.
RecurringMonthlyCost *float64 `json:"recurring_monthly_cost,omitempty" csv:"RecurringMonthlyCost"`
// CommitmentCurrency covers CommitmentCost and RecurringMonthlyCost, not savings or baseline.
// Empty means unknown; presence requires source-proven amounts and currency for every required payment leg.
CommitmentCurrency string `json:"commitment_currency,omitempty" csv:"CommitmentCurrency"`

// Service-specific details (polymorphic)
Details ServiceDetails `json:"details,omitempty" csv:"-"`
Expand Down
36 changes: 36 additions & 0 deletions pkg/common/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,42 @@ func TestPurchaseResult_ExistingCommitmentJSON(t *testing.T) {
assert.True(t, decoded.ExistingCommitment)
}

func TestRecommendation_CommitmentCurrencyJSONAndScaling(t *testing.T) {
t.Parallel()
for _, tt := range []struct {
name string
input string
currency string
}{
{"known EUR", `{"commitment_cost":120,"recurring_monthly_cost":10,"commitment_currency":"EUR"}`, "EUR"},
{"explicit unknown", `{"commitment_cost":120,"recurring_monthly_cost":10,"commitment_currency":""}`, ""},
{"legacy absent", `{"commitment_cost":120,"recurring_monthly_cost":10}`, ""},
} {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var rec Recommendation
require.NoError(t, json.Unmarshal([]byte(tt.input), &rec))
for _, ratio := range []float64{1, 2} {
scaled := ScaleRecommendationCosts(rec, ratio)
payload, err := json.Marshal(scaled)
require.NoError(t, err)
var fields map[string]any
require.NoError(t, json.Unmarshal(payload, &fields))
if tt.currency == "" {
assert.NotContains(t, fields, "commitment_currency")
} else {
assert.Equal(t, tt.currency, fields["commitment_currency"])
}
assert.Equal(t, 120*ratio, fields["commitment_cost"])
assert.Equal(t, 10*ratio, fields["recurring_monthly_cost"])
var roundTrip Recommendation
require.NoError(t, json.Unmarshal(payload, &roundTrip))
assert.Equal(t, scaled, roundTrip)
}
})
}
}

func TestProviderType_String(t *testing.T) {
t.Parallel()
tests := []struct {
Expand Down
Loading