Leon4gr45's picture
Upload folder using huggingface_hub (part 6)
d6f631f verified
Raw
History Blame Contribute Delete
8.76 kB
package subscriptionaddon
import (
"fmt"
"reflect"
"github.com/samber/lo"
"github.com/openmeterio/openmeter/openmeter/entitlement"
"github.com/openmeterio/openmeter/openmeter/productcatalog"
"github.com/openmeterio/openmeter/openmeter/subscription"
"github.com/openmeterio/openmeter/pkg/models"
)
// Apply applies the addon rate card to the target rate card
func (a SubscriptionAddonRateCard) Apply(target productcatalog.RateCard, annotations models.Annotations) error {
typ := reflect.TypeOf(target)
if typ == nil {
return fmt.Errorf("target must not be nil")
}
if typ.Kind() != reflect.Pointer {
return fmt.Errorf("target must be a pointer")
}
if annotations == nil {
return fmt.Errorf("annotations must not be nil")
}
if err := productcatalog.NewRateCardWithOverlay(a.AddonRateCard.RateCard, target).ValidateWith(
productcatalog.ValidateRateCardsShareSameKey,
productcatalog.ValidateRateCardsHaveCompatiblePrice,
productcatalog.ValidateRateCardsHaveCompatibleFeatureKey,
// productcatalog.ValidateRateCardsHaveCompatibleFeatureID, // FIXME(OM-1337): subscriptions handles feature ID incorrectly
productcatalog.ValidateRateCardsHaveCompatibleBillingCadence,
productcatalog.ValidateRateCardsHaveCompatibleEntitlementTemplate,
productcatalog.ValidateRateCardsHaveCompatibleDiscounts,
productcatalog.ValidateRateCardsHaveCompatibleUnitConfig,
); err != nil {
return err
}
return target.ChangeMeta(func(m productcatalog.RateCardMeta) (productcatalog.RateCardMeta, error) {
aMeta := a.AddonRateCard.AsMeta()
tMeta := m.Clone()
// Let's update the price
if aMeta.Price != nil {
switch {
case tMeta.Price == nil:
m.Price = aMeta.Price
case tMeta.Price.Type() == productcatalog.FlatPriceType:
tFlat, _ := tMeta.Price.AsFlat()
aFlat, _ := aMeta.Price.AsFlat()
m.Price = productcatalog.NewPriceFrom(productcatalog.FlatPrice{
Amount: tFlat.Amount.Add(aFlat.Amount),
PaymentTerm: tFlat.PaymentTerm,
})
default:
return m, fmt.Errorf("not supported price type: %s", tMeta.Price.Type())
}
}
// Let's update the entitlement template
if aMeta.EntitlementTemplate != nil {
switch {
case tMeta.EntitlementTemplate == nil:
m.EntitlementTemplate = aMeta.EntitlementTemplate
if aMeta.EntitlementTemplate.Type() == entitlement.EntitlementTypeBoolean {
if _, err := subscription.AnnotationParser.SetBooleanEntitlementCount(annotations, 1); err != nil {
return m, err
}
}
case tMeta.EntitlementTemplate.Type().String() == entitlement.EntitlementTypeBoolean.String():
var err error
count := subscription.AnnotationParser.GetBooleanEntitlementCount(annotations)
annotations, err = subscription.AnnotationParser.SetBooleanEntitlementCount(annotations, count+1)
if err != nil {
return m, err
}
case tMeta.EntitlementTemplate.Type().String() == entitlement.EntitlementTypeMetered.String():
tMetered, _ := tMeta.EntitlementTemplate.AsMetered()
aMetered, _ := aMeta.EntitlementTemplate.AsMetered()
tMetered.IssueAfterReset = lo.ToPtr(lo.FromPtrOr(tMetered.IssueAfterReset, 0) + lo.FromPtrOr(aMetered.IssueAfterReset, 0))
m.EntitlementTemplate = productcatalog.NewEntitlementTemplateFrom(tMetered)
default:
return m, fmt.Errorf("not supported entitlement template type: %s", tMeta.EntitlementTemplate.Type())
}
}
// Let's update the discounts
if aMeta.Discounts.Usage != nil {
targetDiscount := lo.FromPtrOr(tMeta.Discounts.Usage, productcatalog.UsageDiscount{})
targetDiscount.Quantity = targetDiscount.Quantity.Add(aMeta.Discounts.Usage.Quantity)
m.Discounts.Usage = &targetDiscount
}
return m, nil
})
}
// Restore restores the addon rate card to the target rate card
// TODO(galexi): instead of instance parameter, change SubscriptionAddonInstance type
func (a SubscriptionAddonRateCard) Restore(target productcatalog.RateCard, annotations models.Annotations, instanceType productcatalog.AddonInstanceType) error {
// Target has has to be implemented by a pointer otherwise we can't use it as a receiver. Let's check that
typ := reflect.TypeOf(target)
if typ == nil {
return fmt.Errorf("target must not be nil")
}
if typ.Kind() != reflect.Pointer {
return fmt.Errorf("target must be a pointer")
}
if annotations == nil {
return fmt.Errorf("annotations must not be nil")
}
if err := productcatalog.NewRateCardWithOverlay(a.AddonRateCard.RateCard, target).ValidateWith(
productcatalog.ValidateRateCardsShareSameKey,
// productcatalog.ValidateRateCardsHaveCompatiblePrice, // Its okay, we just need to check if single instance, and if so, then set nill
productcatalog.ValidateRateCardsHaveCompatibleFeatureKey,
// productcatalog.ValidateRateCardsHaveCompatibleFeatureID, // FIXME(OM-1337): subscriptions handles feature ID incorrectly
productcatalog.ValidateRateCardsHaveCompatibleBillingCadence,
productcatalog.ValidateRateCardsHaveCompatibleEntitlementTemplate,
productcatalog.ValidateRateCardsHaveCompatibleDiscounts,
// No unit_config compatibility check here (as with price): restore is teardown and never
// reapplies it, so gating on it could strand a removable addon if the target's config drifted.
); err != nil {
return err
}
return target.ChangeMeta(func(m productcatalog.RateCardMeta) (productcatalog.RateCardMeta, error) {
aMeta := a.AddonRateCard.AsMeta()
tMeta := m.Clone()
// Let's update the price
if aMeta.Price != nil {
switch {
case tMeta.Price == nil:
return m, fmt.Errorf("target price is nil, cannot restore price without addon")
case tMeta.Price.Type() == productcatalog.FlatPriceType:
tFlat, _ := tMeta.Price.AsFlat()
aFlat, _ := aMeta.Price.AsFlat()
newAmount := tFlat.Amount.Sub(aFlat.Amount)
if newAmount.IsNegative() {
return m, fmt.Errorf("restoring flat price would yield a negative amount: %s - %s = %s", tFlat.Amount, aFlat.Amount, newAmount)
}
m.Price = productcatalog.NewPriceFrom(productcatalog.FlatPrice{
Amount: newAmount,
PaymentTerm: tFlat.PaymentTerm,
})
case instanceType == productcatalog.AddonInstanceTypeSingle:
m.Price = nil
default:
return m, fmt.Errorf("not supported price type: %s", tMeta.Price.Type())
}
}
// Let's update the entitlement template
if aMeta.EntitlementTemplate != nil {
switch {
case tMeta.EntitlementTemplate == nil:
return m, fmt.Errorf("target entitlement template is nil, cannot restore entitlement template without addon")
case tMeta.EntitlementTemplate.Type().String() == entitlement.EntitlementTypeBoolean.String():
count := subscription.AnnotationParser.GetBooleanEntitlementCount(annotations)
switch {
case count < 0:
return m, fmt.Errorf("received invalid entitlement count annotation value: %d", count)
case count == 0:
return m, fmt.Errorf("target doesn't have boolean entitlement count annotation while has a boolean entitlement template")
case count == 1:
m.EntitlementTemplate = nil
}
if _, err := subscription.AnnotationParser.SetBooleanEntitlementCount(annotations, count-1); err != nil {
return m, err
}
case tMeta.EntitlementTemplate.Type().String() == entitlement.EntitlementTypeMetered.String():
tMetered, _ := tMeta.EntitlementTemplate.AsMetered()
aMetered, _ := aMeta.EntitlementTemplate.AsMetered()
newIssueAfterReset := lo.FromPtrOr(tMetered.IssueAfterReset, 0) - lo.FromPtrOr(aMetered.IssueAfterReset, 0)
if newIssueAfterReset < 0 {
return m, fmt.Errorf("restoring entitlement template would yield a negative issue after reset: %.0f - %.0f = %.0f", lo.FromPtrOr(tMetered.IssueAfterReset, 0), lo.FromPtrOr(aMetered.IssueAfterReset, 0), newIssueAfterReset)
}
tMetered.IssueAfterReset = lo.ToPtr(newIssueAfterReset)
m.EntitlementTemplate = productcatalog.NewEntitlementTemplateFrom(tMetered)
default:
return m, fmt.Errorf("not supported entitlement template type: %s", tMeta.EntitlementTemplate.Type())
}
}
// Let's update the discounts
if aMeta.Discounts.Usage != nil {
if target.AsMeta().Discounts.Usage == nil {
return m, fmt.Errorf("target doesn't have usage discount while addon has a usage discount template")
}
targetDiscount := target.AsMeta().Discounts.Usage.Clone()
if targetDiscount.Quantity.LessThan(aMeta.Discounts.Usage.Quantity) {
return m, fmt.Errorf("target has %.0f usage discount which is less than addon's %.0f", targetDiscount.Quantity.InexactFloat64(), aMeta.Discounts.Usage.Quantity.InexactFloat64())
}
targetDiscount.Quantity = targetDiscount.Quantity.Sub(aMeta.Discounts.Usage.Quantity)
m.Discounts.Usage = &targetDiscount
}
return m, nil
})
}