File size: 4,604 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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | package addondiff
import (
"fmt"
"reflect"
"github.com/samber/lo"
"github.com/openmeterio/openmeter/openmeter/subscription"
subscriptionaddon "github.com/openmeterio/openmeter/openmeter/subscription/addon"
"github.com/openmeterio/openmeter/pkg/datetime"
"github.com/openmeterio/openmeter/pkg/models"
)
func (d *diffable) restore() subscription.AppliesToSpec {
return subscription.NewAppliesToSpec(func(spec *subscription.SubscriptionSpec, _ subscription.ApplyContext) error {
for _, p := range spec.GetSortedPhases() {
pCad, err := spec.GetPhaseCadence(p.PhaseKey)
if err != nil {
return fmt.Errorf("failed to get phase cadence for phase %s: %w", p.PhaseKey, err)
}
for itemsKey := range p.ItemsByKey {
aPer := d.addon.CadencedModel.AsPeriod()
affectingAddonRateCard, ok := lo.Find(d.addon.RateCards, func(rc subscriptionaddon.SubscriptionAddonRateCard) bool {
return rc.AddonRateCard.Key() == itemsKey
})
// If there's no matching key in the addon, we can skip
if !ok {
continue
}
// Let's find the items that should be deleted
rmIdxs := []int{}
for idx, item := range p.ItemsByKey[itemsKey] {
itemPer := item.GetCadence(pCad).AsPeriod()
if !aPer.IsSupersetOf(itemPer) {
continue
}
// Let's try to undo the effects of the addon RateCard
target := item.RateCard.Clone()
if item.Annotations == nil {
item.Annotations = models.Annotations{}
}
for range d.addon.Quantity {
if err := affectingAddonRateCard.Restore(target, item.Annotations, d.addon.Addon.InstanceType); err != nil {
return fmt.Errorf("failed to restore addon rate card %s: %w", affectingAddonRateCard.AddonRateCard.Key(), err)
}
}
item.RateCard = target
// Let's do a stupid check about whether the item can be deleted
chk := zeroRateCardCheck{
itemAnnotations: item.Annotations,
rc: target,
}
if chk.CanDelete() {
rmIdxs = append(rmIdxs, idx)
}
}
filteredItems := make([]*subscription.SubscriptionItemSpec, 0, len(p.ItemsByKey[itemsKey])-len(rmIdxs))
for idx, item := range p.ItemsByKey[itemsKey] {
if lo.Contains(rmIdxs, idx) {
continue
}
filteredItems = append(filteredItems, item)
}
// Two items can be merged if they are
// - subsequent
// - identical (except relative cadence)
mergedItems := make([]*subscription.SubscriptionItemSpec, 0, len(filteredItems))
var targetItem *subscription.SubscriptionItemSpec
for idx := range filteredItems {
if targetItem == nil {
targetItem = filteredItems[idx]
}
if idx+1 >= len(filteredItems) {
break
}
targetCadence := targetItem.GetCadence(pCad)
testItem := filteredItems[idx+1]
testCadence := testItem.GetCadence(pCad)
canMerge := func() bool {
// First, lets check that the rate cards are identical
if !targetItem.RateCard.Equal(testItem.RateCard) {
return false
}
if (targetItem.Annotations == nil) != (testItem.Annotations == nil) {
return false
}
if targetItem.Annotations != nil && !reflect.DeepEqual(targetItem.Annotations, testItem.Annotations) {
return false
}
if !reflect.DeepEqual(targetItem.BillingBehaviorOverride, testItem.BillingBehaviorOverride) {
return false
}
// Second, lets check that they are subsequent
if targetCadence.ActiveTo == nil || !targetCadence.ActiveTo.Equal(testCadence.ActiveFrom) {
return false
}
return true
}()
if canMerge {
combinedPer := targetCadence.AsPeriod().Union(testCadence.AsPeriod())
if combinedPer.From != nil && !combinedPer.From.Equal(pCad.ActiveFrom) {
targetItem.ActiveFromOverrideRelativeToPhaseStart = lo.ToPtr(datetime.ISODurationBetween(pCad.ActiveFrom, *combinedPer.From))
}
if combinedPer.To == nil {
targetItem.ActiveToOverrideRelativeToPhaseStart = nil
}
if combinedPer.To != nil && !combinedPer.To.Equal(pCad.ActiveFrom) {
targetItem.ActiveToOverrideRelativeToPhaseStart = lo.ToPtr(datetime.ISODurationBetween(pCad.ActiveFrom, *combinedPer.To))
}
} else {
mergedItems = append(mergedItems, targetItem)
targetItem = testItem
}
}
if targetItem != nil {
mergedItems = append(mergedItems, targetItem)
}
p.ItemsByKey[itemsKey] = mergedItems
if len(p.ItemsByKey[itemsKey]) == 0 {
delete(p.ItemsByKey, itemsKey)
}
}
}
return nil
})
}
|