File size: 3,191 Bytes
d6f631f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | package subscriptionaddon
import (
"errors"
"fmt"
"time"
"github.com/samber/lo"
"github.com/openmeterio/openmeter/openmeter/productcatalog/addon"
"github.com/openmeterio/openmeter/pkg/models"
"github.com/openmeterio/openmeter/pkg/timeutil"
)
type SubscriptionAddon struct {
models.NamespacedID
models.ManagedModel
models.MetadataModel
Name string `json:"name"`
Description *string `json:"description,omitempty"`
// Maybe break up to AddonID + AddonMeta?
Addon addon.Addon `json:"addon"`
SubscriptionID string `json:"subscriptionID"`
// RateCards is populated from the Addon's RateCards
RateCards []SubscriptionAddonRateCard `json:"rateCards"`
Quantities timeutil.Timeline[SubscriptionAddonQuantity] `json:"quantities"`
}
func (a SubscriptionAddon) GetInstanceAt(t time.Time) (SubscriptionAddonInstance, bool) {
inst := SubscriptionAddonInstance{}
found := false
for _, q := range a.GetInstances() {
if q.CadencedModel.IsActiveAt(t) {
found = true
inst = q
break
}
}
return inst, found
}
func (a SubscriptionAddon) GetInstances() []SubscriptionAddonInstance {
quantities := a.Quantities
// Deleted things should not get into memory but let's look out anyways
if a.DeletedAt != nil {
quantities = quantities.Before(*a.DeletedAt)
}
if len(quantities.GetTimes()) == 0 {
return []SubscriptionAddonInstance{}
}
periods := quantities.GetOpenPeriods()
if len(periods) < 1 {
// This should never happen as len > 0
return []SubscriptionAddonInstance{}
}
periods = periods[1:]
if len(periods) != len(quantities.GetTimes()) {
// This should never happen
return []SubscriptionAddonInstance{}
}
if lo.SomeBy(periods, func(period timeutil.OpenPeriod) bool {
return period.From == nil
}) {
// This should never happen
return []SubscriptionAddonInstance{}
}
return lo.Map(periods, func(period timeutil.OpenPeriod, idx int) SubscriptionAddonInstance {
quantity := quantities.GetAt(idx)
cad, _ := models.NewCadencedModelFromPeriod(period)
return SubscriptionAddonInstance{
NamespacedID: a.NamespacedID,
ManagedModel: a.ManagedModel,
MetadataModel: a.MetadataModel,
Addon: a.Addon,
SubscriptionID: a.SubscriptionID,
Name: a.Name,
Description: a.Description,
RateCards: a.RateCards,
Quantity: quantity.GetValue().Quantity,
CadencedModel: cad,
}
})
}
type CreateSubscriptionAddonInput struct {
models.MetadataModel
AddonID string `json:"addonID"`
SubscriptionID string `json:"subscriptionID"`
InitialQuantity CreateSubscriptionAddonQuantityInput `json:"initialQuantity"`
}
func (i CreateSubscriptionAddonInput) Validate() error {
var errs []error
if i.AddonID == "" {
errs = append(errs, errors.New("addonID is required"))
}
if i.SubscriptionID == "" {
errs = append(errs, errors.New("subscriptionID is required"))
}
if err := i.InitialQuantity.Validate(); err != nil {
errs = append(errs, fmt.Errorf("initialQuantity: %w", err))
}
if i.InitialQuantity.Quantity == 0 {
errs = append(errs, errors.New("initialQuantity.quantity cannot be 0"))
}
return errors.Join(errs...)
}
|